【BZOJ】【1030】【JSOI2007】文本生成器
AC自动机/DP
Orz ZYF
玛雅快要省选了,赶紧复(xue)习(xi)一下AC自动机……
其实在AC自动机上DP并没有当初想的那么复杂……就是把DP的转移关系换成了AC自动机上的边而已(不过这题好像搞成了Trie图?)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************************** 2 Problem: 1030 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:208 ms 7 Memory:7148 kb 8 ****************************************************************/ 9 10 //BZOJ 1030 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=6010,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 const int MOD=10007; 32 int n,m,cnt=1; 33 struct Trie{ 34 int ch[26],cnt,fail; 35 bool sign; 36 }T[N]; 37 inline int id(char c){return c-'A';} 38 void ins(char *s){ 39 int x=1,y; 40 rep(i,strlen(s)){ 41 y=id(s[i]); 42 if (T[x].ch[y]==0) 43 T[x].ch[y]=++cnt; 44 x=T[x].ch[y]; 45 } 46 T[x].sign=1; 47 } 48 int Q[N]; 49 void make_fail(){ 50 int l=0,r=-1; 51 Q[++r]=1; 52 while(l<=r){ 53 int x=Q[l++],y,j; 54 rep(i,26){ 55 j=T[x].fail; 56 while(j && !T[j].ch[i]) j=T[j].fail; 57 if (T[x].ch[i]){ 58 y=T[x].ch[i]; 59 T[y].fail=j ? T[j].ch[i] : 1; 60 T[y].sign=T[y].sign|T[T[y].fail].sign; 61 Q[++r]=y; 62 }else T[x].ch[i]=j ? T[j].ch[i] : 1; 63 } 64 } 65 } 66 int f[110][N][2]; 67 void dp(){ 68 f[0][1][0]=1; 69 rep(i,m) F(j,1,cnt) rep(k,26) F(l,0,1) 70 if(T[T[j].ch[k]].sign) 71 (f[i+1][T[j].ch[k]][1]+=f[i][j][l])%=MOD; 72 else (f[i+1][T[j].ch[k]][l]+=f[i][j][l])%=MOD; 73 } 74 char s[N]; 75 int main(){ 76 #ifndef ONLINE_JUDGE 77 freopen("1030.in","r",stdin); 78 freopen("1030.out","w",stdout); 79 #endif 80 n=getint(); m=getint(); 81 F(i,1,n){ 82 scanf("%s",s); 83 ins(s); 84 } 85 make_fail(); 86 dp(); 87 int ans=0; 88 F(i,1,cnt) (ans+=f[m][i][1])%=MOD; 89 printf("%d\n",ans); 90 return 0; 91 }
1030: [JSOI2007]文本生成器
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2224 Solved: 923
[Submit][Status][Discuss]
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