题目描述 Description
|
JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版。该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文 |
输入描述 Input Description
|
输入文件的第一行包含两个正整数,分别是使用者了解的单词总数N (<= 60),GW文本生成器 v6生成的文本固定长度M;以下N行,每一行包含一个使用者了解的单词。这里所有单词及文本的长度不会超过100,并且只可能包含英文大写字母A..Z |
输出描述 Output Description
|
一个整数,表示可能的文章总数。只需要知道结果模10007的值。
|
样例输入 Sample Input
|
2 2
|
样例输出 Sample Output
|
100
|
数据范围及提示 Data Size & Hint
|
|
肯定是一个AC自动机类题。典型的AC自动机上DP类题。
首先把这些单词都放在一棵Trie树上,单词结尾打一下danger标记,本题的题目意思就是说在AC自动机上走M步,使得每一步都不走在danger节点的方案数。
那么我们就开始DP 设f(i,j)表示现在在第i号点,走了j步的方案数。转移的话就比较简单了。f(i,j)可以转移到f(ch[i][k],j+1),前提是ch[i][k]不是危险节点。本题我用的是新版AC自动机,对每一个转移都一视同仁,不用管什么走Fail边。
1 #include<iostream>
2 #include<algorithm>
3 #include<cstdio>
4 #include<queue>
5 #include<cmath>
6 #include<cstring>
7 using namespace std;
8 typedef long long LL;
9 typedef pair<int,int> PII;
10 #define mem(a,b) memset(a,b,sizeof(a))
11 inline int read()
12 {
13 int x=0,f=1;char c=getchar();
14 while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
15 while(isdigit(c)){x=x*10+c-'0';c=getchar();}
16 return x*f;
17 }
18 const int maxn=6010,MOD=10007;
19 int n,m,tot,ch[maxn][30],Fail[maxn],danger[maxn],dp[110][maxn],ans,sum=1;
20 bool vis[110][maxn];
21 char s[110];
22 int id(char c){return c-'A';}
23 void insert(char *s)
24 {
25 int len=strlen(s),now=0;
26 for(int i=0;i<len;i++)
27 {
28 int c=id(s[i]);
29 if(!ch[now][c])ch[now][c]=++tot;
30 now=ch[now][c];
31 }
32 danger[now]=1;
33 }
34 void getFail()
35 {
36 queue<int> Q;
37 for(int i=0;i<26;i++)if(ch[0][i])Q.push(ch[0][i]);
38 while(Q.size())
39 {
40 int u=Q.front();Q.pop();
41 for(int i=0;i<26;i++)
42 {
43 int &v=ch[u][i];
44 if(!v){v=ch[Fail[u]][i];continue;}
45 Q.push(v);
46 int j=Fail[u];
47 while(j && !ch[j][i])j=Fail[j];
48 Fail[v]=ch[j][i];
49 danger[v]|=danger[Fail[v]];
50 }
51 }
52 }
53 int main()
54 {
55 n=read();m=read();
56 for(int i=0;i<n;i++)scanf("%s",s),insert(s);
57 getFail();
58 dp[0][0]=1;
59 for(int i=1;i<=m;i++)
60 for(int j=0;j<=tot;j++)
61 if(!danger[j])
62 for(int k=0;k<26;k++)
63 {
64 int &v=ch[j][k];
65 if(!danger[v])dp[i][v]=(dp[i][v]+dp[i-1][j])%MOD;
66 }
67 for(int i=0;i<=tot;i++)if(!danger[i])ans=(ans+dp[m][i])%MOD;
68 for(int i=1;i<=m;i++)sum=(sum*26)%MOD;
69 printf("%d
",(sum-ans+8*MOD)%MOD);
70 return 0;
71 }