bzoj-1030 文本生成器

来源:互联网 发布:医学中英文翻译软件 编辑:程序博客网 时间:2024/05/16 06:03

题意:

给出一个n个单词的字典,单词长度<=100;

求长度为m的随机字符串中有多少个串至少包括一个单词;

n<=60,m<=100;


题解:

好久没有写AC自动机啦,如今还记得模板真是难得;

然而这似乎是Trie图?总之写出来不差几句话;

首先至少包括一个单词这个条件不太好弄;

那就转化一下,求不含单词的字符串个数;

然后就想办法处理这个;

定义状态,f[i][j]表示长度为i的字符串,最后几位的状态在Trie图上的结点编号;

那么转移显然了:

最开始f[0][1]是1;

从一个点到下一个点累加f;

如果目前结点代表的单词在字典中,f值为0;

有个小坑,就是可能有单词包括另一个单词,这时也要将大单词里的小单词标上标记;

就是在找fail的时候顺便标一下,具体可以看代码;

不过代码很丑= =,我反正是写不出来比较短的AC自动机。。。


代码:


#include<queue>#include<stdio.h>#include<string.h>#include<algorithm>#define N 128#define M 6000#define mod 10007#define pr pair<int,int>using namespace std;int next[M][26],fail[M],root=1,tot=1;int f[N][M];char str[N];bool is[M];int pow(int x,int y){int ret=1;while(y){if(y&1)ret=ret*x%mod;x=x*x%mod;y>>=1;}return ret;}void Insert(char *s){int p=root,index;while(*s!='\0'){index=*s-'A';if(!next[p][index])next[p][index]=++tot;p=next[p][index];s++;}is[p]=1;}void Build(){queue<int>q;int x,p,i,temp;q.push(root);while(!q.empty()){x=q.front(),q.pop();for(i=0;i<26;i++){p=next[x][i];temp=fail[x];while(temp){if(next[temp][i]){if(p&&is[next[temp][i]])is[p]=1;(p?fail[p]:next[x][i])=next[temp][i];break;}temp=fail[temp];}if(!temp)(p?fail[p]:next[x][i])=root;if(p)q.push(p);}}}int main(){int n,m,i,j,k,index,ans;scanf("%d%d",&n,&m);for(i=1;i<=n;i++){scanf("%s",str);Insert(str);}Build();f[0][1]=1;for(i=1;i<=m;i++){for(j=1;j<=tot;j++){for(k=0;k<26;k++){index=next[j][k];if(is[index])continue;f[i][index]=(f[i][index]+f[i-1][j])%mod;}}}for(i=1,ans=0;i<=tot;i++){ans+=f[m][i];ans%=mod;}printf("%d\n",((pow(26,m)-ans)%mod+mod)%mod);return 0;}



0 0