BZOJ 1030 [JSOI2007]文本生成器
1030: [JSOI2007]文本生成器
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2624 Solved: 1087
[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
HINT
Source
题解:acdp的入门题
补集转换,变为求有danger的点的数量。一开始总是转不过弯来,现在懂了:窝萌设串前缀为考虑的阶段,那么在这个阶段要干什么呢?要"推进一步自动机"对不对,那么再加上一个维数表示考虑到了自动机上的节点就行了,具体实现的时候窝是直接写在了自动机里的f[m]。
然后再说一下这个endmark,可以把ta想象成一个病毒,一开始在所有的end_node里,在窝萌getfail的时候,会顺着得到的fail指针传播,然后就没有然后了。。。具体实现就在getfail的时候维护一下就行。
自动机还是一个挺神奇的东西,哪天补补PAM玩玩。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<stack> 6 #include<queue> 7 #include<cstring> 8 #define PAU putchar(' ') 9 #define ENT putchar('\n') 10 #define trans(p) while(p&&!p->tx[c])p=p->fail;if(!p)p=root; 11 using namespace std; 12 const int maxn=10000+10,maxnode=10000+10,sig=26,inf=-1u>>1,mod=10007; 13 struct node{ 14 node*tx[sig],*fail;int f[110];bool v;node(){v=false;memset(f,0,sizeof(f));} 15 }ac[maxnode],*nodecnt=ac,*root=nodecnt++; 16 node*get(node*x){return x?x:root;} 17 node*tran(node*x,int c){while(x&&!x->tx[c])x=x->fail;if(!x)x=root;return x;} 18 void insert(char*s){ 19 node*x=root; 20 for(int i=0;s[i];i++){ 21 int c=s[i]-'A'; 22 if(!x->tx[c])x->tx[c]=nodecnt++; 23 x=x->tx[c]; 24 }x->v=true;return; 25 } 26 void getfail(){ 27 queue<node*>Q;for(int c=0;c<sig;c++)if(root->tx[c])Q.push(root->tx[c]); 28 while(!Q.empty()){ 29 node*x=Q.front();Q.pop(); 30 for(int c=0;c<sig;c++)if(x->tx[c]){ 31 node*p=tran(x->fail,c);x->tx[c]->fail=get(p->tx[c]); 32 if(p->tx[c]&&p->tx[c]->v)x->tx[c]->v=true;Q.push(x->tx[c]); 33 } 34 }return; 35 } 36 void dp(int x){ 37 for(node*t=ac;t!=nodecnt;t++){ 38 if(!t->v&&t->f[x-1])for(int c=0;c<sig;c++){ 39 node*p=tran(t,c);get(p->tx[c])->f[x]+=t->f[x-1]%=mod; 40 } 41 }return; 42 } 43 char s[maxn];int n,m; 44 inline int read(){ 45 int x=0,sig=1;char ch=getchar(); 46 for(;!isdigit(ch);ch=getchar())if(ch=='-')sig=0; 47 for(;isdigit(ch);ch=getchar())x=10*x+ch-'0'; 48 return sig?x:-x; 49 } 50 inline void write(int x){ 51 if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x; 52 int len=0,buf[15];while(x)buf[len++]=x%10,x/=10; 53 for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return; 54 } 55 int main(){ 56 n=read();m=read();int ans=1,ans2=0; 57 for(int i=1;i<=n;i++)scanf("%s",s),insert(s); 58 getfail();root->f[0]=1; 59 for(int i=1;i<=m;i++)dp(i),ans=ans*26%mod; 60 for(node*t=ac;t!=nodecnt;t++)if(!t->v)(ans2+=t->f[m])%=mod; 61 write((ans-ans2+mod)%mod); 62 return 0; 63 }