[bzoj1030][JSOI2007]文本生成器
AC自动机入门题。。。。
然而我只想入门以防KOI出题人送分(其实是智商硬伤)。。。YY一下感觉AC自动机还很正常然而写起来就各种跪
显然是用总的串数减去不可读的串数。。。而不可读串数就是AC自动机上走m步(从根出发),并且不经过任何一个完整的可识别单词的路径数。
“不经过任何一个完整的可识别单词”就是说走的每个节点都不是结束节点,并且fail指针指向的也不是结束节点。(这就保证从根到这个节点上的路径不包含完整的单词)
把AC自动机建出来,然后在上面dp
f[i][j]表示走了i步,最后在自动机的j号节点上的路径数。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 const int sxt=10007;const int maxn=66;const int maxlen=103; 7 8 int fail[maxn*maxlen],ch[maxn*maxlen][26],dl[maxn*maxlen],tot,len,l,r; 9 bool tag[maxn*maxlen];//是结尾节点,或者fail指向结尾节点 10 char s[maxlen]; 11 12 int f[2][maxn*maxlen],pre,now; 13 int i,j,k,n,m,ans; 14 15 inline void insert(int len){ 16 register int i,now; 17 for(i=1;i<=len;i++)s[i]-='A'; 18 for(now=0,i=1;i<=len;i++) 19 now=ch[now][s[i]]?ch[now][s[i]]:ch[now][s[i]]=++tot; 20 tag[now]=1; 21 } 22 inline void getfail(){ 23 register int i,j,tmp; 24 l=0,r=1,dl[1]=0; 25 while(l<r) 26 for(j=0,i=dl[++l];j<26;j++)if(ch[i][j]){ 27 for(tmp=fail[i];tmp&&!ch[tmp][j];tmp=fail[tmp]); 28 fail[ch[i][j]]=i?ch[tmp][j]:0, 29 tag[ch[i][j]]|=tag[ch[tmp][j]]; 30 dl[++r]=ch[i][j]; 31 } 32 } 33 34 int main(){ 35 register int j,k,tmp; 36 scanf("%d%d",&n,&m); 37 for(i=ans=1;i<=m;i++){ 38 ans*=26;if(ans>=sxt)ans%=sxt; 39 } 40 for(i=1;i<=n;i++){ 41 for(s[len=1]=getchar();s[1]<'A'||s[1]>'Z';s[1]=getchar()); 42 while(s[len]>='A'&&s[len]<='Z')s[++len]=getchar(); 43 len--,insert(len); 44 } 45 getfail(); 46 f[0][0]=1; 47 for(i=1,now=1,pre=0;i<=m;i++,swap(now,pre)) 48 for(memset(f[now],0,(tot+1)<<2),j=dl[l=1];l<=r;j=dl[++l])if(!tag[j]&&f[pre][j]) 49 for(k=0;k<26;k++){ 50 for(tmp=j;tmp&&!ch[tmp][k];tmp=fail[tmp]); 51 tmp=ch[tmp][k]; 52 if(!tag[tmp]) 53 f[now][tmp]+=f[pre][j],f[now][tmp]-=f[now][tmp]>=sxt?sxt:0; 54 } 55 for(i=0;i<=tot;i++) 56 ans-=f[pre][i],ans+=ans<0?sxt:0; 57 printf("%d\n",ans); 58 return 0; 59 }
代码跑得奇慢而且毫无可读性QAQ