【BZOJ 1030】 [JSOI2007]文本生成器

1030: [JSOI2007]文本生成器

Time Limit: 1 Sec  Memory Limit: 162 MB

Submit: 2017  Solved: 834

[Submit][Status]

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

AC自动机+dp。

首先把所求转化成 26^m减去一个单词都不包含的方案数。

接下来把单词插到AC自动机上进行dp。

f[i][j]表示走到AC自动机的j号结点当前单词长度为i的方案数。

转移就是枚举下一位的26个字母,看是否可行(如果下一位在j的子节点中出现,若被标记为单词的结尾,就不能转移)

注意对于长度为i的单词,枚举AC自动机上的结点标号j,如果f[i][j]=0,说明长度为i-1的单词没有能转移到j上的,因此f[i][j]自然也不能转移到i+1。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cstdlib>
#define mod 10007
using namespace std;
char s[100];
queue<int> q;
int n,m,tot,ans,f[105][10005];
struct AC
{
	int son[30],ne,last;
	bool mark;
}tree[10005];
void Insert(char str[])
{
	int l=strlen(str),x=0;
	for (int i=0;i<l;i++)
	{
		int y=str[i]-'A';
		if (!tree[x].son[y])
			tree[x].son[y]=++tot;
		x=tree[x].son[y];
	}
	tree[x].mark=true;
}
void Make_fail()
{
	for (int i=0;i<26;i++)
		if (tree[0].son[i])
			q.push(tree[0].son[i]);
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		for (int i=0;i<26;i++)
			if (tree[x].son[i])
			{
				int y=tree[x].son[i];
				q.push(y);
				int v=tree[x].ne;
				while (v&&!tree[v].son[i])
					v=tree[v].ne;
				tree[y].ne=v=tree[v].son[i];
				tree[y].last=tree[v].mark?v:tree[v].last;
			}
	}
}
void dp()
{
	f[0][0]=1;
	for (int i=0;i<m;i++)
		for (int j=0;j<=tot;j++)
			if (f[i][j])
				for (int k=0;k<26;k++)
				{
					int v=j;
					while (v&&!tree[v].son[k])
						v=tree[v].ne;
					v=tree[v].son[k];
					if (!tree[v].mark&&!tree[v].last)
						f[i+1][v]=(f[i+1][v]+f[i][j])%mod;
				}
	for (int i=0;i<=tot;i++)
		ans=(ans+f[m][i])%mod;
}
int main()
{
        scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
		scanf("%s",s),Insert(s);
	Make_fail();
	dp();
	int x=1;
	for (int i=1;i<=m;i++)
		x=(x*26)%mod;
	cout<<(x-ans+mod)%mod<<endl;
	return 0;
}

感悟:

1.注意这道题有一个last标记,因为可能j不是当前字符串的结尾,是别的字符串的结尾

时间: 2024-07-29 18:29:35

【BZOJ 1030】 [JSOI2007]文本生成器的相关文章

bzoj 1030: [JSOI2007]文本生成器 (ac自己主动机上的dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2635  Solved: 1090 [Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务.编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们如今使用的是GW文本生成器v6版.该软件能够随机生成一些文章―――总是生成一篇长度固定且全然随机的文章-- 也就是说,生成的文章中

BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )

之前一直没调出来T^T...早上刷牙时无意中就想出错在哪里了... 对全部单词建AC自动机, 然后在自动机上跑dp, dp(i, j)表示匹配到了第i个字符, 在自动机上的j结点的方案数, 然后枚举A~Z进行转移. -------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; #define idx(c) ((c) -

bzoj 1030 [JSOI2007]文本生成器(AC自动机+DP)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3059  Solved: 1255[Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完

bzoj 1030: [JSOI2007]文本生成器 (ac自动机上的dp)

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 2635  Solved: 1090 [Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中

BZOJ 1030 [JSOI2007]文本生成器(AC自动机)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1030 [题目大意] 求出包含任意一个给定串的串数量 [题解] 我们求出不包含任意一个给定串的数量,用全集去减即可, 对于给定串建立AC自动机,用1节点作为根,0节点向1连全字符集转移作为超级源, 那么0->match能匹配所有不包含给定串的串, 记dp[i][j]表示匹配了i长度,匹配到AC自动机j节点的串数量, 统计之后取补集即可. [代码] #include <cstdio&g

bzoj 1030: [JSOI2007]文本生成器

AC自动机的fail,然后用fail搞搞DP,不懂不懂,,,,啊啊啊啊啊啊 1 #include<bits/stdc++.h> 2 #define N 1000005 3 #define LL long long 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 inline int ra() 7 { 8 int x=0,f=1; char ch=getchar(); 9 while (ch<'0' || ch>'9') {if (

1030: [JSOI2007]文本生成器

1030: [JSOI2007]文本生成器 https://www.lydsy.com/JudgeOnline/problem.php?id=1030 分析: AC自动机+dp. 正难则反,求满足的,可以求出不满足的,用总的减去.所以考虑如何就出所有的长度为m的串里,没有出现任何一个单词的个数. 建立AC自动机,然后会有一些点是一定不能走的,这些点要么是某些单词的结尾,或者是包含了某些单词(以它结尾的串的后缀是一个单词). 然后f[i][j]表示当前有多少位,在AC自动机的哪个位置的方案数.枚举

【BZOJ】1030: [JSOI2007]文本生成器(递推+ac自动机)

http://www.lydsy.com/JudgeOnline/problem.php?id=1030 其实做了1009也不会感到很难了,无非将kmp变成了ac自动机. 设f[i,j]表示前i个串当前匹配到j的节点的方案数.. 然后自己想. sb错1:ac自动机的节点开小了(自己想错了..以为最多节点就是层数×分支(26)....于是..其实是n个串的长度和...) sb错2:ac自动机bfs时没有维护信息啊!!只维护了一个fail... #include <cstdio> #include

BZOJ1030:[JSOI2007]文本生成器

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4859  Solved: 2019[Submit][Status][Discuss] Description JSOI交给队员ZGX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些战舰狗,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中每个字