【BZOJ1030】[JSOI2007]文本生成器
【题意】
给定一些单词,我们定义一篇可读文章至少包含一个这样的单词,求长度为M的可读文章总数。
【分析】
用前几题的方法可以求长度为M的不可读的文章总数Sum,所以我们可以用26^M-Sum来求出可读文章的总数。不过这题的N*Len太大,也就是AC自动机的节点太多,如果用矩阵乘法求解用爆空间,所以我直接DP了。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 5 const int Maxn=80; 6 const int Maxl=110; 7 const int Mod=10007; 8 9 int n,m,tot,len,total; 10 int q[Maxl*Maxn],f[Maxl][Maxl*Maxn]; 11 char s[Maxl]; 12 13 struct node 14 { 15 int son[27],fail; 16 bool mark; 17 }t[Maxn*Maxl]; 18 19 void floy() 20 { 21 tot=0,total=0; 22 memset(f,0,sizeof(f)); 23 memset(q,0,sizeof(q)); 24 for(int i=1;i<=Maxl*Maxn;i++) 25 { 26 t[i].mark=0; 27 for(int j=1;j<=26;j++) t[i].son[j]=0; 28 } 29 } 30 31 void read_trie() 32 { 33 tot=0; 34 int i,j; 35 scanf("%d%d",&n,&m); 36 for(i=1;i<=n;i++) 37 { 38 int x,ind; 39 scanf("%s",s+1); 40 len=strlen(s+1); 41 x=0; 42 for(j=1;j<=len;j++) 43 { 44 ind=s[j]-'A'+1; 45 if(!t[x].son[ind]) t[x].son[ind]=++tot; 46 x=t[x].son[ind]; 47 if(j==len) t[x].mark=1; 48 } 49 } 50 } 51 52 void build_AC() 53 { 54 int i,j,x,y; 55 q[++q[0]]=0; 56 for(i=1;i<=q[0];i++) 57 { 58 x=q[i];y=t[x].fail; 59 for(j=1;j<=26;j++) 60 { 61 if(t[x].son[j]) 62 { 63 t[t[x].son[j]].fail=x?t[y].son[j]:0; 64 if(t[t[t[x].son[j]].fail].mark) t[t[x].son[j]].mark=1; 65 q[++q[0]]=t[x].son[j]; 66 } 67 else t[x].son[j]=t[y].son[j]; 68 } 69 } 70 } 71 72 void dp() 73 { 74 int i,j,k,v; 75 f[0][0]=1; 76 for(i=1;i<=m;i++) 77 for(j=0;j<=tot;j++) if(f[i-1][j]) 78 for(k=1;k<=26;k++) 79 { 80 v=t[j].son[k]; 81 if(!t[v].mark) f[i][v]=(f[i][v]+f[i-1][j])%Mod; 82 } 83 for(i=0;i<=tot;i++) 84 total=(total+f[m][i])%Mod; 85 } 86 87 int pow(int x) 88 { 89 int ans=26,sum=1; 90 while(x) 91 { 92 if(x&1) sum=(sum*ans)%Mod; 93 ans=(ans*ans)%Mod; 94 x=x>>1; 95 } 96 return sum; 97 } 98 99 int main() 100 { 101 read_trie(); 102 build_AC(); 103 dp(); 104 printf("%d\n",(pow(m)-total+Mod)%Mod); 105 }
2016-07-12 10:10:32