BZOJ 1030 文本生成器
很老的题目了,很早以前学AC自动机的时候就A过一次
今天算是复习啦
我们可以把问题转化成一个给定字符串都没出现的字符串有多少个
我们建立AC自动机,设dp[i][j]表示走了i步当前在j节点上
在DP的过程中不转移单词节点即可
#include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int maxn=6010; const int mod=10007; int n,m,cnt=1,ans; char s[maxn]; int t[maxn][26]; int fail[maxn]; int dp[102][maxn]; bool end[maxn]; queue<int>Q; void insert(){ scanf("%s",s+1); int len=strlen(s+1),now=1; for(int i=1;i<=len;++i){ int id=s[i]-'A'; if(!t[now][id])t[now][id]=++cnt; now=t[now][id]; }end[now]=true; } void build_fail(){ Q.push(1);fail[1]=0; while(!Q.empty()){ int u=Q.front();Q.pop(); end[u]|=end[fail[u]]; for(int i=0;i<26;++i){ int k=fail[u]; while(k&&!t[k][i])k=fail[k]; if(t[u][i]){ fail[t[u][i]]=k?t[k][i]:1; Q.push(t[u][i]); }else t[u][i]=k?t[k][i]:1; } }return; } void Get_DP(){ dp[0][1]=1; for(int i=0;i<m;++i){ for(int j=1;j<=cnt;++j){ if(!dp[i][j])continue; for(int k=0;k<26;++k){ int now=t[j][k]; if(end[now])continue; dp[i+1][now]+=dp[i][j]; if(dp[i+1][now]>=mod)dp[i+1][now]-=mod; } } }return; } int pow_mod(int v,int p){ int tmp=1; while(p){ if(p&1)tmp=tmp*v%mod; v=v*v%mod;p>>=1; }return tmp; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i)insert(); build_fail(); Get_DP(); ans=0; for(int i=1;i<=cnt;++i){ ans=ans+dp[m][i]; if(ans>=mod)ans-=mod; } ans=pow_mod(26,m)-ans; ans=(ans+mod)%mod; printf("%d\n",ans); return 0; }