[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;
}

浙公网安备 33010602011771号