【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 }
[BZOJ1030]

 

2016-07-12 10:10:32

posted @ 2016-07-12 10:08  konjak魔芋  阅读(220)  评论(0编辑  收藏