bzoj1030 [JSOI2007]文本生成器 - AC自动机+dp
JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,
他们现在使用的是GW文本生成器v6版。该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文
章—— 也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,
那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串)。但是,即使按照这样的
标准,使用者现在使用的GW文本生成器v6版所生成的文章也是几乎完全不可读的?。ZYX需要指出GW文本生成器 v6
生成的所有文本中可读文本的数量,以便能够成功获得v7更新版。你能帮助他吗?
Input
输入文件的第一行包含两个正整数,分别是使用者了解的单词总数N (<= 60),GW文本生成器 v6生成的文本固
定长度M;以下N行,每一行包含一个使用者了解的单词。这里所有单词及文本的长度不会超过100,并且只可能包
含英文大写字母A..Z
Output
一个整数,表示可能的文章总数。只需要知道结果模10007的值。
Sample Input
2 2 A B
Sample Output
100
Hint
题解:
题目中应该很好想到ac自动机来解决这道题,这里我们可以换一种思维方式,问知道的文章不好得出
结果,可以想有多少不认识的文章,就是说,给定的单词一个都不能出现。就是说如果该单词有就认
识,那么单词都要避开。
f[i][j]表示到了i这一位,总共m个,即长度,然后,到了j这一个点,可以获得的方案数。
那么就需要在建立Trie图的时候处理一下。
看这个垃圾图,x,y,z点,y指向z,z为标记节点,因为z为y的后缀
所以y包涵z,y也是不和法的,所以y也需要标记为不可到达。
然后就是转移了,复杂度可以压过。
1 #include<cstring> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstdio> 6 #include<queue> 7 #define mod 10007 8 using namespace std; 9 10 int n,m,ans=1,res,cnt=1,f[107][6007]; 11 struct Node 12 { 13 int c[26],suf; 14 bool flag; 15 }trie[6007]; 16 char ch[107]; 17 18 void insert() 19 { 20 int now=1,len=strlen(ch); 21 for (int i=0;i<len;i++) 22 { 23 if (!trie[now].c[ch[i]-'A']) trie[now].c[ch[i]-'A']=++cnt; 24 now=trie[now].c[ch[i]-'A']; 25 } 26 trie[now].flag=true; 27 } 28 void make_AC() 29 { 30 for (int i=0;i<26;i++) 31 trie[0].c[i]=1; 32 queue<int>q;while(!q.empty()) q.pop(); 33 trie[1].suf=0; 34 q.push(1); 35 while(!q.empty()) 36 { 37 int u=q.front();q.pop(); 38 for (int i=0;i<26;i++) 39 if (trie[u].c[i]) 40 { 41 trie[trie[u].c[i]].suf=trie[trie[u].suf].c[i]; 42 if (trie[trie[trie[u].c[i]].suf].flag) trie[trie[u].c[i]].flag=true; 43 q.push(trie[u].c[i]); 44 } 45 else trie[u].c[i]=trie[trie[u].suf].c[i]; 46 } 47 } 48 inline void dp(int x) 49 { 50 for (int i=1;i<=cnt;i++) 51 { 52 if (trie[i].flag||f[x-1][i]==0) continue; 53 for (int j=0;j<26;j++) 54 f[x][trie[i].c[j]]=(f[x][trie[i].c[j]]+f[x-1][i])%mod; 55 } 56 } 57 int main() 58 { 59 scanf("%d%d",&n,&m); 60 for (int i=1;i<=n;i++) 61 { 62 scanf("%s",ch); 63 insert(); 64 } 65 make_AC(); 66 f[0][1]=1; 67 for (int i=1;i<=m;i++) dp(i); 68 for (int i=1;i<=m;i++) 69 ans=(ans*26)%mod; 70 for (int i=1;i<=cnt;i++) 71 if (trie[i].flag==0) res=(res+f[m][i])%mod; 72 printf("%d\n",(ans-res+mod)%mod); 73 }