【JSOI2007】文本生成器

【JSOI2007】文本生成器

by AmanoKumiko

Description

JSOI 交给队员 ZYX 一个任务,编制一个称之为「文本生成器」的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是 GW 文本生成器 v6 版。该软件可以随机生成一些文章――总是生成一篇长度固定且完全随机的文章——也就是说,生成的文章中每个字节都是完全随机的。如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章\(a\)包含单词\(b\),当且仅当单词\(b\)是文章\(a\)的子串)。

但是,即使按照这样的标准,使用者现在使用的 GW 文本生成器 v6 版所生成的文章也是几乎完全不可读的。ZYX 需要指出 GW 文本生成器 v6 生成的所有文本中可读文本的数量,以便能够成功获得 v7 更新版。你能帮助他吗?

Input

输入的第一行包含两个正整数,分别是使用者了解的单词总数\(N\),GW 文本生成器 v6 生成的文本固定长度\(M\)

以下\(N\)行,每一行包含一个使用者了解的单词。

Output

一个整数,表示可能的文章总数。只需要知道结果模\(10007\)的值。

Sample Input

2 2
A
B

Sample Output

100

Data Constraint

对于全部数据\(1<=N<=60\),所有单词及文本的长度不会超过100,并且只可能包含英文大写字母。

Solution

正难则反

1.建自动机

2.给可能经过单词结尾的位置打上标记

3.设\(f[i][j]\)表示当前长度为\(j\),在自动机上第\(i\)个点的不合法方案数

4.\(ans=26^m-Σf[i][m]\)

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define mo 10007
#define N 70
#define L 110
#define P 6010

queue<int>q;
int n,m,ans=1,sum,f[P][L],len;
char ch[L];
struct ACM{
	int son[P][26],fail[P],flag[P],tot,Q[P],he;
	void insert(){
		int u=1;
		F(i,1,len)son[u][ch[i]-'A']?u=son[u][ch[i]-'A']:u=son[u][ch[i]-'A']=++tot;
		flag[u]=1;
	}
	void build(){
		F(i,0,25)son[0][i]=1;q.push(1);
		while(!q.empty()){
			int u=q.front();q.pop();Q[++he]=u;
			F(i,0,25){
				int v=son[u][i],Fail=fail[u];
				if(!v){son[u][i]=son[Fail][i];continue;}
				fail[v]=son[Fail][i];
				flag[v]|=flag[u];
				q.push(v);
			}
		}
		F(i,1,he)flag[Q[i]]|=flag[fail[Q[i]]];//标记
	}
}t;

int main(){
	scanf("%d%d",&n,&m);t.tot=1;
	F(i,1,n)scanf("%s",ch+1),len=strlen(ch+1),t.insert();
	t.build();
	f[1][0]=1;
	F(j,0,m-1) F(i,1,t.tot)if(f[i][j]){F(k,0,25)if(!t.flag[t.son[i][k]])(f[t.son[i][k]][j+1]+=f[i][j])%=mo;}
	F(i,1,t.tot)(sum+=f[i][m])%=mo;//dp
	F(i,1,m)(ans*=26)%=mo;
	printf("%d",(ans-sum+mo)%mo);
	return 0;
}
posted @ 2021-02-04 19:28  冰雾  阅读(85)  评论(0编辑  收藏  举报