您的位置:首页 > Web前端 > JavaScript

[Bzoj1030][JSOI2007]文本生成器(AC自动机)(dp)

2017-11-27 15:11 337 查看

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

.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); }

[p] 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: