BZOJ1030[JSOI2007]文本生成器——AC自动机+DP

题目描述

  JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,
他们现在使用的是GW文本生成器v6版。该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文
章—— 也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,
那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串)。但是,即使按照这样的
标准,使用者现在使用的GW文本生成器v6版所生成的文章也是几乎完全不可读的?。ZYX需要指出GW文本生成器 v6
生成的所有文本中可读文本的数量,以便能够成功获得v7更新版。你能帮助他吗?

输入

  输入文件的第一行包含两个正整数,分别是使用者了解的单词总数N (<= 60),GW文本生成器 v6生成的文本固
定长度M;以下N行,每一行包含一个使用者了解的单词。这里所有单词及文本的长度不会超过100,并且只可能包
含英文大写字母A..Z

输出

  一个整数,表示可能的文章总数。只需要知道结果模10007的值。

样例输入

2 2
A
B

样例输出

100
 
这道题正着做很麻烦,要考虑好多情况还要去重。那么我们不妨换个思路:不求有多少满足的,求有多少不满足的,然后再用26^m减掉不满足的就是满足的了。那么问题就变成了怎么找不满足的?显然是要根据了解的那些单词来找,只要在trie树上走m步且不遇到终止节点,就说明这个m个字符长的字符串不满足。那么只要在AC自动机上作dp就行了,设f[i][j]表示走了i步,走到编号为j的节点的不满足的方案数。f[i][j]+=f[i-1][k],其中k是j的一个子节点。∑f[m][i]就是总共的不满足方案数了。
最后附上代码。
  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<algorithm>
  8 using namespace std;
  9 struct tree
 10 {
 11     int fail;
 12     int vis[27];
 13     int end;
 14 }a[10010];
 15 char s[100010];
 16 int cnt;
 17 int n;
 18 int m;
 19 int tot=1;
 20 int f[105][10010];
 21 int mod=10007;
 22 int ans;
 23 void build(char *s)
 24 {
 25     int l=strlen(s);
 26     int now=0;
 27     for(int i=0;i<l;i++)
 28     {
 29         int x=(s[i]-'A');
 30         if(a[now].vis[x]==0)
 31         {
 32             a[now].vis[x]=++cnt;
 33         }
 34         now=a[now].vis[x];
 35     }
 36     a[now].end|=1;
 37 }
 38 void bfs()
 39 {
 40     queue<int>q;
 41     for(int i=0;i<26;i++)
 42     {
 43         if(a[0].vis[i]!=0)
 44         {
 45             a[a[0].vis[i]].fail=0;
 46             q.push(a[0].vis[i]);
 47         }
 48     }
 49     while(!q.empty())
 50     {
 51         int now=q.front();
 52         q.pop();
 53         for(int i=0;i<26;i++)
 54         {
 55             if(a[now].vis[i]==0)
 56             {
 57                 a[now].vis[i]=a[a[now].fail].vis[i];
 58             }
 59             else
 60             {
 61                 a[a[now].vis[i]].end|=a[a[a[now].fail].vis[i]].end;
 62                 a[a[now].vis[i]].fail=a[a[now].fail].vis[i];
 63                 q.push(a[now].vis[i]);
 64             }
 65         }
 66     }
 67 }
 68 int main()
 69 {
 70     scanf("%d%d",&n,&m);
 71     for(int i=1;i<=n;i++)
 72     {
 73         scanf("%s",s);
 74         build(s);
 75     }
 76     bfs();
 77     for(int i=1;i<=m;i++)
 78     {
 79         tot*=26;
 80         tot%=mod;
 81     }
 82     f[0][0]=1;
 83     for(int i=1;i<=m;i++)
 84     {
 85         for(int j=0;j<=cnt;j++)
 86         {
 87             for(int k=0;k<26;k++)
 88             {
 89                 if(!a[a[j].vis[k]].end)
 90                 {
 91                     f[i][a[j].vis[k]]+=f[i-1][j];
 92                     f[i][a[j].vis[k]]%=mod;
 93                 }
 94             }
 95         }
 96     }
 97     for(int i=0;i<=cnt;i++)
 98     {
 99         ans+=f[m][i];
100         ans%=mod;
101     }
102     printf("%d",(tot+mod-ans)%mod);
103 }
View Code

猜你喜欢

转载自www.cnblogs.com/Khada-Jhin/p/9162409.html
今日推荐