BZOJ 1030 [JSOI2007]文本生成器

1030: [JSOI2007]文本生成器

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 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

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 }

 

你可能感兴趣的:(BZOJ 1030 [JSOI2007]文本生成器)