bzoj1030 [JSOI2007]文本生成器
Description
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
A
B
Sample Output
100
正解:$AC$自动机+$DP$。
首先我们构造好$AC$自动机,并且记录一下每一位是否可能形成匹配,就是记录每一位的$val$和$last$就行了。
设$f[i][j]$表示统计到文本前$i$位,自动机上第$j$位,没有匹配的方案数,去掉能匹配的情况,直接大力转移就行了。
最后我们再用总方案数减去不匹配的方案数,就是至少有一个匹配的方案数。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define rhl (10007) 15 #define inf (1<<30) 16 #define N (10010) 17 #define il inline 18 #define RG register 19 #define ll long long 20 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 21 22 using namespace std; 23 24 int f[110][N],q[N],n,m,len,ans; 25 char s[N]; 26 27 struct AC_auto{ 28 29 int ch[N][26],val[N],nxt[N],last[N],sz; 30 31 il void insert(char *s,RG int len){ 32 RG int x=0,c; 33 for (RG int i=1;i<=len;++i){ 34 c=s[i]-65; 35 if (!ch[x][c]) ch[x][c]=++sz; 36 x=ch[x][c]; 37 } 38 val[x]++; return; 39 } 40 41 il void build(){ 42 RG int h=0,t=0; 43 for (RG int c=0;c<26;++c) 44 if (ch[0][c]) nxt[ch[0][c]]=last[ch[0][c]]=0,q[++t]=ch[0][c]; 45 while (h<t){ 46 RG int x=q[++h],v,j; 47 for (RG int c=0;c<26;++c){ 48 v=ch[x][c]; if (!v){ ch[x][c]=ch[nxt[x]][c]; continue; } 49 q[++t]=v,nxt[v]=last[v]=0,j=nxt[x]; while (j && !ch[j][c]) j=nxt[j]; 50 nxt[v]=ch[j][c],last[v]=val[nxt[v]] ? nxt[v] : last[nxt[v]]; 51 } 52 } 53 return; 54 } 55 56 }AC; 57 58 il int gi(){ 59 RG int x=0,q=1; RG char ch=getchar(); 60 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 61 if (ch=='-') q=-1,ch=getchar(); 62 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 63 return q*x; 64 } 65 66 il int qpow(RG int a,RG int b){ 67 RG int ans=1; 68 while (b){ 69 if (b&1) ans=ans*a%rhl; 70 a=a*a%rhl,b>>=1; 71 } 72 return ans; 73 } 74 75 il void work(){ 76 n=gi(),m=gi(); 77 for (RG int i=1;i<=n;++i){ 78 scanf("%s",s+1); 79 len=strlen(s+1); 80 AC.insert(s,len); 81 } 82 AC.build(); f[0][0]=1; 83 for (RG int i=0;i<m;++i) 84 for (RG int j=0;j<=AC.sz;++j){ 85 if (!f[i][j]) continue; 86 for (RG int k=0;k<26;++k){ 87 if (AC.val[AC.ch[j][k]] || AC.last[AC.ch[j][k]]) continue; 88 f[i+1][AC.ch[j][k]]+=f[i][j]; 89 if (f[i+1][AC.ch[j][k]]>=rhl) f[i+1][AC.ch[j][k]]-=rhl; 90 } 91 } 92 for (RG int i=0;i<=AC.sz;++i){ ans+=f[m][i]; if (ans>=rhl) ans-=rhl; } 93 printf("%d\n",(qpow(26,m)-ans+rhl)%rhl); return; 94 } 95 96 int main(){ 97 File("txt"); 98 work(); 99 return 0; 100 }