bzoj1030(AC自动机)

1030: [JSOI2007]文本生成器

Time Limit: 1 Sec   Memory Limit: 162 MB
Submit: 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

2 2
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;
}

你可能感兴趣的:(bzoj1030(AC自动机))