P4052 [JSOI2007]文本生成器

P4052 [JSOI2007]文本生成器

AC自动机+dp

优秀题解传送门

设f[ i ][ j ]表示串的长度为 i ,当前在 j 点时不可识别的串的方案数

最后用总方案数减去不可识别方案数就是答案了

因为题解写的很好所以我就只在代码中加点注释了(逃

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int mod=10007;
struct data{
    int nxt[26],fail,end;
}a[6002];
int n,m,cnt,ans=1,f[102][6002];
char q[102];
inline void Trie_build(){
    scanf("%s",q);
    int u=0,len=strlen(q);
    for(int i=0;i<len;++i){
        int p=q[i]-'A';
        if(!a[u].nxt[p]) a[u].nxt[p]=++cnt;
        u=a[u].nxt[p];
    }++a[u].end;
}
inline void AC_build(){
    queue <int> h;
    for(int i=0;i<26;++i) if(a[0].nxt[i]) h.push(a[0].nxt[i]);
    while(!h.empty()){
        int x=h.front(); h.pop();
        for(int i=0;i<26;++i){
            int &to=a[x].nxt[i];
            if(to){
                a[to].fail=a[a[x].fail].nxt[i];
                a[to].end|=a[a[to].fail].end; //如果该串的后缀是可识别的那么这个串也一定是可识别的
                h.push(to);
            }else to=a[a[x].fail].nxt[i];
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) Trie_build();
    AC_build();
    f[0][0]=1;
    for(int i=1;i<=m;++i)
        for(int j=0;j<=cnt;++j)
            for(int k=0;k<26;++k)
                if(!a[a[j].nxt[k]].end) //不可识别
                    f[i][a[j].nxt[k]]=(f[i][a[j].nxt[k]]+f[i-1][j])%mod;
    for(int i=1;i<=m;++i) ans=ans*26%mod;
    for(int i=0;i<=cnt;++i) ans=(ans-f[m][i]+mod)%mod; //总方案数-不可识别方案数
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/kafuuchino/p/9623238.html