1030: [JSOI2007]文本生成器
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 2781 Solved: 1151
[ 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
A
B
Sample Output
100
解题思路:
先对每个单词做一遍AC自动机,然后用fg[i][j]表示若当前匹配到i,且文本选择到j的种类。i在这里是指trie树上的点。然后用记忆化搜索来完成。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n,m;
int root,now_sum;
char c[100];
const int M_ax=10007;
const int cg=160000;
int zhi[6101];
int ch[6101][27];
int dui[6101][27];
int f[156001];
int q[160000];
bool b[6101][27];
int fg[6101][101];
struct data
{
int now,wei;
}g[160000];
int zhuan(char x)
{
int zan=int(x)-64;
return zan;
}
void dfs(int o,int len,int xian)
{
if (len==xian+1) zhi[o]=1;
if (len>xian) return;
int zu=zhuan(c[len-1]);
if (ch[o][zu])
{
dfs(dui[o][zu],len+1,xian);
}else
{
ch[o][zu]=true;
++now_sum; dui[o][zu]=now_sum;
dfs(now_sum,len+1,xian);
}
}
void ready()
{
f[0]=-1;
int tail=1; int head=0; q[tail]=root;
while (head!=tail)
{
head=(head+1)%cg;
for (int i=1;i<=26;++i)
if (ch[q[head]][i])
{
int now=f[q[head]];
while (now!=-1 && ch[now][i]==false)
{
now=f[now];
}
if (now==-1) now=0;else now=dui[now][i];
f[dui[q[head]][i]]=now;
if (zhi[now]==1) zhi[dui[q[head]][i]]=1;
tail=(tail+1)%cg;
q[tail]=dui[q[head]][i];
}
}
}
void Init()
{
getchar();
scanf("%s",c); int lg=strlen(c);
dfs(root,1,lg);
}
int main()
{
memset(zhi,0,sizeof(zhi));
scanf("%d %d",&n,&m);
root=0; now_sum=0;
memset(ch,false,sizeof(ch));
for (int i=1;i<=n;++i)
{
Init();
}
ready();
memset(b,true,sizeof(b));
int tail=1; int head=0; fg[0][0]=1; g[tail].now=0; g[tail].wei=0; b[0][0]=false;
while (head!=tail)
{
head=(head+1)%cg;
if(g[head].wei==m) continue;
for (int i=1;i<=26;++i)
{
int now=g[head].now;
while (now!=0 && !ch[now][i])
{
now=f[now];
}
if (ch[now][i] && zhi[dui[now][i]]!=1)
{
fg[dui[now][i]][g[head].wei+1]=(fg[dui[now][i]][g[head].wei+1]+fg[g[head].now][g[head].wei])%M_ax;
if (b[dui[now][i]][g[head].wei+1])
{
b[dui[now][i]][g[head].wei+1]=false;
tail=(tail+1)%cg;
g[tail].now=dui[now][i]; g[tail].wei=g[head].wei+1;
}
}else if(now==0 && ch[now][i]==false)
{
fg[0][g[head].wei+1]=(fg[0][g[head].wei+1]+fg[g[head].now][g[head].wei])%M_ax;
if (b[0][g[head].wei+1])
{
b[0][g[head].wei+1]=false;
tail=(tail+1)%cg;
g[tail].now=0; g[tail].wei=g[head].wei+1;
}
}
}
b[g[head].now][g[head].wei]=true;
}
long long other=0,sum=26;
for (int i=0;i<=now_sum;++i)
{
other=(other+fg[i][m])%M_ax;
}
for (int i=2;i<=m;++i)
{
sum=(sum*26)%M_ax;
}
sum=(sum-other+M_ax)%M_ax;
cout<<sum;
}