BZOJ1030: [JSOI2007]文本生成器(AC自动机)
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 5984 Solved: 2523
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
HINT
Source
感觉自己好菜啊这种题都想不出来qwq。。
刚开始想的是容斥—>把所有合法的统计出来再减去重复的!!没错我就这么xjb容斥了半个小时qwq。。
看了一下大佬的题解瞬间思路明了。。。
考虑经典补集转化思想:这题问的是可读的,我们可以转化为总的-不可读的。
总的就是$26^m$
不可读的考虑DP。设$f[i][j]$表示长度为$i$时,在自动机上第$j$个位置有多少不可读的情况
开始时$f[0][0] = 1$,转移的时候枚举一下出边
注意!!如果一个点的$fail$指针指向的位置不可读,那么该节点也是不可读的!
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
const int MAXN = 1e5 + 10, B = 26, mod = 10007;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M;
int ch[MAXN][26], fail[MAXN], tot = 0, root = 0, val[MAXN];
char s[101];
void insert(char *s) {
int N = strlen(s + 1), now = root;
for(int i = 1; i <= N; i++) {
int x = s[i] - 'A';
if(!ch[now][x]) ch[now][x] = ++tot;
now = ch[now][x];
}
val[now] = 1;//不能经过
}
void GetFail() {
queue<int> q;
for(int i = 0; i < B; i++) if(ch[root][i]) q.push(ch[root][i]);
while(!q.empty()) {
int p = q.front(); q.pop();
for(int i = 0; i < B; i++)
if(ch[p][i]) fail[ch[p][i]] = ch[fail[p]][i], q.push(ch[p][i]);
else ch[p][i] = ch[fail[p]][i];
val[p] |= val[fail[p]];
}
}
int f[101][MAXN]; // 当前长度为i,在自动机的地j号节点
int solve() {
f[0][0] = 1;
for(int i = 1; i <= M; i++) {
for(int j = 0; j <= tot; j++) {
for(int k = 0; k < B; k++) {//枚举出边
int son = ch[j][k];
if(val[son]) continue;
f[i][son] = (f[i][son] % mod+ f[i - 1][j] % mod) % mod;
}
}
}
int ans = 0;
for(int i = 0; i <= tot; i++)
ans = (ans + f[M][i] % mod) % mod;
int sum = 1;
for(int i = 1; i <= M; i++) sum = (26 * sum) % mod;
return (sum - ans + mod) % mod;
}
main() {
#ifdef WIN32
freopen("a.in", "r", stdin);
#endif
scanf("%d %d", &N, &M);
for(int i = 1; i <= N; i++)
scanf("%s", s + 1), insert(s);
GetFail();
printf("%d", solve() % mod);
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python OpenCV读取中文路径图像的方法
- Java如何基于wsimport调用wcf接口
- Python装饰器结合递归原理解析
- Windows上php5.6操作mongodb数据库示例【配置、连接、获取实例】
- 浅谈keras通过model.fit_generator训练模型(节省内存)
- PHP实现通过文本文件统计页面访问量功能示例
- 解决Alexnet训练模型在每个epoch中准确率和loss都会一升一降问题
- python里的单引号和双引号的有什么作用
- 在PHP中输出JS语句以及乱码问题的解决方案
- 使用Keras中的ImageDataGenerator进行批次读图方式
- php用xpath解析html的代码实例讲解
- PHP操作路由器实现方法示例
- python能在浏览器能运行吗
- Python使用OpenPyXL处理Excel表格
- php如何比较两个浮点数是否相等详解