[BZOJ1030][JSOI2007]文本生成器(AC自动机+DP)
Solution
考虑算出所有不包含给定字符串的方案数,在用总数减去就行了
f[i][j]表示到第i个字符串,当前停在自动机上j点的方案数
Code
#include <cstdio> #include <algorithm> #include <cstring> #define N 6010 using namespace std; char s[110]; const int mo=10007; int n,m,f[110][N],T[N][27],fail[N],tot=1,mark[N],q[N],sum=1,Ans; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Insert(){ scanf("%s\n",&s); int len=strlen(s),now=1; for(int i=0;i<len;++i){ if(!T[now][s[i]-64]) T[now][s[i]-64]=++tot; now=T[now][s[i]-64]; } mark[now]=1; } void getfail(){ for(int i=1;i<=26;++i) T[0][i]=1; int k,now,h=0,t=0;q[++t]=1; while(h<t){ mark[now=q[++h]]|=mark[fail[now]]; for(int i=1;i<=26;++i) if(T[now][i]){ k=fail[now]; while(!T[k][i]) k=fail[k]; fail[q[++t]=T[now][i]]=T[k][i]; } } } int main(){ n=read(),m=read(); for(int i=1;i<=n;++i) Insert(); getfail(); f[0][1]=1; for(int i=0;i<m;++i) for(int j=1;j<=tot;++j) for(int k=1;k<=26;++k) if(!mark[j]){ int now=j; while(!T[now][k]) now=fail[now]; now=T[now][k]; (f[i+1][now]+=f[i][j])%=mo; } for(int i=1;i<=m;++i) sum=sum*26%mo; for(int i=0;i<=tot;++i) if(!mark[i]) Ans=(Ans+f[m][i])%mo; printf("%d\n",(sum-Ans+mo)%mo); return 0; }