首页 > 学院 > 开发设计 > 正文

bzoj1030: [JSOI2007]文本生成器

2019-11-08 01:13:57
字体:
来源:转载
供稿:网友

bzoj1030: [JSOI2007]文本生成器

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

题目大意

给定n个模板串,求出至少包含1个模板串的长度为m的串的个数。

题解

乍一看和DNA Sequence非常相似。但发现这题里模板串较多较长,所以无法用矩阵快速次幂的方法解决。但是这题的要求构造的文本串长度较小,考虑动态规划。 考虑求出所有不包含任何模板串的文本串的个数,再用总数减去。 用AC自动机构造出所有的边。 设f[i][j]为走了i步到j点的方案总数。那么f[i][j]显然可以转移到f[i+1][ch[j][k]],那么初始化f[0][0]=1,按照顺序dp即可。 答案即为26m−Σf[m][i]

#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int max_size = 6000 + 10, ch_size = 26, mod = 10007, M = 100 + 10;char s[M];int n, m, d[M][max_size], ans;struct Trie{ int ch[max_size][ch_size]; int val[max_size], f[max_size], q[max_size]; int idx['Z'+1], sz; Trie() {sz = 1; for(char i = 'A'; i <= 'Z'; i++) idx[i] = i-'A';} void insert(char *s){ int u = 0, len = strlen(s); for(int i = 0; i < len; i++){ int x = idx[s[i]]; if(!ch[u][x]) ch[u][x] = sz++; u = ch[u][x]; } val[u] = 1; } void get_fail(){ int l = 1, r = 1; for(int i = 0; i < ch_size; i++){ int u = ch[0][i]; if(u){ q[r++] = u; } } while(l < r){ int t = q[l++]; if(val[f[t]]) val[t] = 1; for(int i = 0; i < ch_size; i++){ int &u = ch[t][i]; if(!u){ u = ch[f[t]][i]; continue; } q[r++] = u; int v = f[t]; while(v && !ch[v][i]) v = f[v]; f[u] = ch[f[t]][i]; } } } void solve(){ d[0][0] = 1; for(int i = 1; i <= m; i++){ for(int j = 0; j < sz; j++){ if(val[j]) continue; for(int k = 0; k < ch_size; k++) d[i][ch[j][k]] = (d[i][ch[j][k]] + d[i-1][j]) % mod; } } int tot1 = 1, tot2 = 0;; for(int i = 1; i <= m; i++) tot1 = (tot1 * 26) % mod; for(int i = 0; i < sz; i++) if(!val[i]) tot2 = (tot2 + d[m][i]) % mod; ans = (tot1 - tot2 + mod) % mod; }}ac;void init(){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++){ scanf("%s", s); ac.insert(s); }}void work(){ ac.get_fail(); ac.solve(); PRintf("%d/n", ans);}int main(){ init(); work(); return 0;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表