【BZOJ1030】【JSOI2007】文本生成器
我现在连AC自动姬都不会,怎么办嘛QAQ
原题:
JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,
他们现在使用的是GW文本生成器v6版。该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文
章—— 也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,
那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串)。但是,即使按照这样的
标准,使用者现在使用的GW文本生成器v6版所生成的文章也是几乎完全不可读的?。ZYX需要指出GW文本生成器 v6
生成的所有文本中可读文本的数量,以便能够成功获得v7更新版。你能帮助他吗?
N <= 60,所有单词及文本的长度不会超过100
如果一个串的后缀不能选,这个串当然也不能选
延伸到AC自动姬上就是如果一个串fail指向的节点不能选,这个节点就不能选
然后就可以预处理出那些节点不能选
然后用f[i][j]表示在文本串走到i时AC自动姬上走到j节点的方案数
首先外层枚举i,再枚举j,如果j可选,就枚举26个字符k,f[i][j]就给j沿着k往下能走到的状态(包括走fail)v贡献
能理解这道题怎么写,但是似乎不能往更广泛的地方延伸,想不动东西……感觉状态不是很好啊QAQ
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int dalao=10007; 8 int rd(){int z=0,mk=1; char ch=getchar(); 9 while(ch<'0'||ch>'9'){if(ch=='-')mk=-1; ch=getchar();} 10 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 11 return z*mk; 12 } 13 int n,m; 14 char s[110]; int ls; 15 int nxt[6100][26],fl[6100],tt=0; 16 int q[6100],hd=0; 17 bool mk[6100]; 18 int f[110][6100]; 19 void ist(){ 20 int tmp=0; 21 for(int i=1;i<=ls;++i){ 22 if(!nxt[tmp][s[i]-'A']) nxt[tmp][s[i]-'A']=++tt; 23 tmp=nxt[tmp][s[i]-'A']; 24 } 25 mk[tmp]=true; 26 } 27 void gtac(){ 28 for(int i=0;i<26;++i)if(nxt[0][i]) q[++hd]=nxt[0][i]; 29 for(int k=1;k<=hd;++k)for(int i=0;i<26;++i){ 30 if(!nxt[q[k]][i]) nxt[q[k]][i]=nxt[fl[q[k]]][i]; 31 else{ 32 fl[nxt[q[k]][i]]=nxt[fl[q[k]]][i],q[++hd]=nxt[q[k]][i]; 33 mk[nxt[q[k]][i]]|=mk[nxt[fl[q[k]]][i]]; 34 } 35 } 36 } 37 int main(){//freopen("ddd.in","r",stdin); 38 cin>>n>>m; 39 for(int i=1;i<=n;++i) scanf("%s",s+1),ls=strlen(s+1),ist(); 40 gtac(); 41 f[0][0]=1; 42 for(int i=1;i<=m;++i)for(int j=0;j<=tt;++j)if(!mk[j] && f[i-1][j]) 43 for(int k=0;k<26;++k) 44 f[i][nxt[j][k]]=(f[i][nxt[j][k]]+f[i-1][j])%dalao; 45 int bwl=0,ans=1; 46 for(int i=1;i<=m;++i) ans=(ans*26)%dalao; 47 for(int i=0;i<=tt;++i)if(!mk[i]) bwl=(bwl+f[m][i])%dalao; 48 cout<<(ans-bwl+dalao)%dalao<<endl; 49 return 0; 50 }