bzoj1030[JSOI2007]文本生成器

bzoj1030[JSOI2007]文本生成器

题意:

给出一个字典和一个长度,要求有多少个这个长度的字符串里含有子串为字典里的单词。字符串和字典里的字符都为大写字母。单词数≤60,字符串及单词长度≤100。

题解:

在AC自动机上跑dp,求不含字典单词的个数,再用总个数减。f[i][j]表示当前处理第i个位置,在trie上的节点为j。f[i][j]=sum{f[i+1][ch[x][k]]},x为j的fail祖先,为k为大写字母,不能走到val为1的节点。注意val的处理,特别是getfail中的“if(val[ch[y][i]])val[ch[x][i]]=1;”一句。

代码:

 1 #include <cstring>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <queue>
 5 #define maxn 10000
 6 #define inc(i,j,k) for(int i=j;i<=k;i++)
 7 #define mod 10007
 8 using namespace std;
 9 
10 int n,m,sz,ch[maxn][26],fail[maxn],ans,f[150][maxn]; bool val[maxn];
11 void insert(char *s){
12     int x=0,len=strlen(s+1); inc(i,1,len){if(!ch[x][s[i]-'A'])ch[x][s[i]-'A']=++sz; x=ch[x][s[i]-'A'];}
13     val[x]=1;
14 }
15 queue <int> q;
16 void getfail(){
17     inc(i,0,25)if(ch[0][i])q.push(ch[0][i]),fail[ch[0][i]]=0;
18     while(!q.empty()){
19         int x=q.front(); q.pop();
20         inc(i,0,25)if(ch[x][i]){
21             int y=fail[x]; while(y&&!ch[y][i])y=fail[y]; if(ch[y][i])fail[ch[x][i]]=ch[y][i];
22             if(val[ch[y][i]])val[ch[x][i]]=1; q.push(ch[x][i]);
23         }
24     }
25 }
26 char str[150];
27 int main(){
28     scanf("%d%d",&n,&m); inc(i,1,n)scanf("%s",str+1),insert(str); ans=1; getfail();
29     inc(i,1,m)ans=ans*26%mod; f[0][0]=1;
30     inc(i,1,m)inc(j,0,sz)if(!val[j]&&f[i-1][j]){
31         inc(k,0,25){
32             int x=j; while(x&&!ch[x][k])x=fail[x]; f[i][ch[x][k]]=(f[i][ch[x][k]]+f[i-1][j])%mod;
33         }
34     }
35     inc(i,0,sz)if(!val[i]){
36         ans=(ans-f[m][i])%mod; if(ans<0)ans+=mod;
37     }
38     printf("%d",ans); return 0;
39 }

 

20160621

posted @ 2016-07-24 16:37  YuanZiming  阅读(150)  评论(0编辑  收藏