比较简单的一道题,想到了解法却总是过不了,照着黄学长的代码改了半天才过;
开始我写的是以0为根建trie图,一直错,改成了黄学长的以1为根就对了。可能是以0为根的话要注意一些细节的处理。。。
以后还是以1为根写吧,感觉这样代码很自然需要注意的问题又少。
这个题的想法就是在AC自动机上dp计数,dp[i][j]表示以j结尾的长度为i的串,满足条件的不太好统计,
我们发现不满足条件的很好统计,只要在trie图上跑出不包含val等于1的点的一条长为m的路即可;
#include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> using namespace std; const int maxn=6010; const int mod=10007; int f[105][maxn],ans1,ans2,n,m,tot,vis[maxn],q[maxn],head,tail; struct node{ int son[26],f,cnt,v; }ch[maxn]; char s[maxn]; void add(char s[]){ int u=1,len; len=strlen(s); for(int i=0;i<len;++i){ int c=s[i]-'A'; if(!ch[u].son[c]){ch[u].son[c]=++tot;} u=ch[u].son[c]; } vis[u]=1; } void pre(){ head=tail=0; ch[1].f=0; q[++tail]=1; while(head<tail){ int now=q[++head]; for(int i=0;i<26;++i){ int u=ch[now].son[i]; if(!u){ch[now].son[i]=ch[ch[now].f].son[i];continue;} int v=ch[now].f; while(!ch[v].son[i])v=ch[v].f; ch[u].f=ch[v].son[i]; vis[u]|=vis[ch[v].son[i]]; q[++tail]=u; } } } int main(){ tot=1; cin>>n>>m; for(int i=0;i<26;++i)ch[0].son[i]=1; for(int i=1;i<=n;++i){ scanf("%s",s);add(s); } pre(); f[0][1]=1; for(int ss=1;ss<=m;++ss) for(int i=1;i<=tot;++i){ if(vis[i]||!f[ss-1][i])continue; for(int j=0;j<26;++j){ int k=i; while(!ch[k].son[j])k=ch[k].f; f[ss][ch[k].son[j]]=(f[ss][ch[k].son[j]]+f[ss-1][i])%mod; } } ans2=1;ans1=0; for(int i=1;i<=m;++i)ans2=(ans2*26)%mod; for(int i=1;i<=tot;++i){ if(!vis[i])ans1=(ans1+f[m][i])%mod; } printf("%d",(ans2-ans1+mod)%mod); //system("pause"); return 0; }