1030: [JSOI2007]文本生成器
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 3953 Solved: 1614
[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
题意:求长度为m且含有至少一个模板串的字符串个数
好神啊
含有至少一个不好求,那就求不含模板串的然后总数减
计数问题组合数学做不了就考虑DP
f[i][j]表示长度为i匹配到自动机上节点j的不含模板串的方案数
转移 f[i][j]-->f[i+1][t[j].ch[k]]
如何判断一个串不含模板串?首先f[i][j]已经保证1..i-1是不含模板串的啦,只要保证第i个字符加入后也不含就行了
ins时模板串终点打标记,本身且Fail祖先没有标记就说明AC自动机上j结尾的没有模板串
但是有的字符模板串里没有啊?给root把孩子补全就行了【实际上不补全也是可以的,反正默认走到了根,最后f[m][根]也统计】
思路和KMP一样,都是一边生成字符串一边在KMP/AC自动机上匹配,
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=,M=,MOD=;
int n,m;
char s[N];
struct node{
int ch[],fail,val;
}t[M];
int sz;
void ins(char s[]){
int u=,n=strlen(s+);
for(int i=;i<=n;i++){
int c=s[i]-'A';
if(!t[u].ch[c]) t[u].ch[c]=++sz;
u=t[u].ch[c];
}
t[u].val=;
}
int q[M],head,tail;
void getAC(){
head=tail=;
for(int i=;i<;i++){
if(!t[].ch[i]) t[].ch[i]=++sz;
q[tail++]=t[].ch[i];
}
while(head!=tail){
int u=q[head++];
t[u].val|=t[t[u].fail].val;
for(int i=;i<;i++){
int &v=t[u].ch[i];
if(!v) {v=t[t[u].fail].ch[i];continue;}
t[v].fail=t[t[u].fail].ch[i];
q[tail++]=v;
}
}
}
int f[N][M],ans;
void dp(){
f[][]=;
for(int i=;i<=m;i++){
for(int j=;j<=sz;j++) if(!t[j].val&&f[i-][j]!=)
for(int k=;k<;k++) if(!t[t[j].ch[k]].val)
f[i][t[j].ch[k]]=(f[i][t[j].ch[k]]+f[i-][j])%MOD;
}
for(int j=;j<=sz;j++) ans=(ans+f[m][j])%MOD;
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);//printf("hi %d %d nm\n",n,m);
for(int i=;i<=n;i++) scanf("%s",s+),ins(s);
getAC();
dp();
int tmp=;
for(int i=;i<=m;i++) tmp=(tmp*)%MOD;
printf("%d",(tmp-ans+MOD)%MOD);
}