[Bzoj1030][JSOI2007]文本生成器(AC自动机)(dp)
1030: [JSOI2007]文本生成器
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 5254 Solved: 2172
[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
分析:
让我们找可以读懂的,我们可以换过来求总方案 - 不可以读懂的方案
不可以读懂的很显然可以用dp求,定义dp[i][j],表示当前长度为i,在trie树上的结点j的方案树,
很显然不可以转移到有权值或者fail指针一路到根节点的结点中有权值的结点。(这个用继承就好了)。
然后就可以转移走了,复杂度最坏(2600 * n * m)
跑的还挺快,100多ms
AC代码:
# include <iostream> # include <cstdio> # include <cstring> using namespace std; const int N = 1e4; char str[112]; struct node{ int next[26]; int fail; int count; }; int stack ,tot; node q ; void clear(int k){ memset(q[k].next,0,sizeof q[k].next); q[k].fail = q[k].count = 0; } void insert(){ int p = 0; int len = strlen(str),v; for(int i = 0;i < len;i++){ v = str[i] - 'A'; if(!q[p].next[v]){ q[p].next[v] = ++tot; clear(tot); } p = q[p].next[v]; } q[p].count++; } void bfs_fail(){ int h = 0,t = 0; for(int i = 0;i < 26;i++){ if(q[0].next[i])stack[t++] = q[0].next[i]; } int u,to; while(h != t){ u = stack[h++]; for(int i = 0;i < 26;i++){ int &v = q[u].next[i];to = q[u].fail; if(!v){ v = q[to].next[i]; }else { q[stack[t++] = v].fail = q[to].next[i]; } q[u].count += q[to].count; } } } int n,m,dp[112][6012],mod = 10007; int cmd(int k){ int a = 1,b = 26; while(k){ if(k & 1)a = a * b % mod; b = b * b % mod; k >>= 1; } return a; } int main(){ scanf("%d %d",&n,&m); clear(0); for(int i = 1;i <= n;i++){ scanf("%s",str); insert(); } bfs_fail(); dp[0][0] = 1; for(int t = 0;t < m;t++){ for(int i = 0;i <= tot;i++){ for(int j = 0;j < 26;j++){ int v = q[i].next[j]; if(!dp[t][i] || q[i].count || q[v].count)continue; (dp[t + 1][v] += dp[t][i]) %= mod; } } } int ans = cmd(m); for(int i = 0;i <= tot;i++)(ans -= dp[m][i] - mod) %= mod; printf("%d\n",ans); }
- 【BZOJ1030】[JSOI2007]文本生成器【AC自动机】【计数DP】
- [AC自动机 DP] BZOJ 1030 [JSOI2007] 文本生成器
- 【BZOJ1030】【JSOI2007】文本生成器(AC自动机,DP)
- [BZOJ1030] [JSOI2007]文本生成器(AC自动机 + DP)
- BZOJ 1030 [JSOI2007]文本生成器 (AC自动机 + DP)
- BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )
- BZOJ 1030: [JSOI2007]文本生成器 DP,AC自动机
- BZOJ 1030: [JSOI2007]文本生成器 [AC自动机 DP]
- bzoj1030 [JSOI2007]文本生成器(AC+dp)
- [bzoj1030][JSOI2007]文本生成器【AC自动机】
- [BZOJ1030][JSOI2007]文本生成器(AC自动机+dp)
- 【AC自动机】【bzoj 1030】: [JSOI2007]文本生成器
- 【bzoj 1030】 [JSOI2007]文本生成器(AC自动机+dp)
- bzoj1030 [JSOI2007] 文本生成器(ACAM+dp)
- BZOJ 1030: [JSOI2007]文本生成器 AC自动机
- [JSOI2007][BZOJ1030] 文本生成器|AC自动机|动态规划
- bzoj 1030 [JSOI2007]文本生成器(AC自动机+DP)
- BZOJ_1030_[JSOI2007]_文本生成器_(AC自动机+DP)
- BZOJ.1030.[JSOI2007]文本生成器(AC自动机 DP)
- [BZOJ1030][JSOI2007]文本生成器(AC自动机+dp)