[JSOI2007]文本生成器

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自动机,在建fail指针的时候延续终止标识符,直接dp即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
	int x=0,f=1;char ch=gc();
	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x<0)    putchar('-'),x=-x;
	if (x>9)	print(x/10);
	putchar(x%10+'0');
}
const int N=1e2,M=60,Mod=1e4+7;
struct S1{
	int trie[N*M+10][26],fail[N*M+10],root,tot;
	bool End[N*M+10];
	void insert(char *s){
		int len=strlen(s),p=root;
		for (int i=0;i<len;i++){
			if (!trie[p][s[i]-'A'])	trie[p][s[i]-'A']=++tot;
			p=trie[p][s[i]-'A'];
		}
		End[p]=1;
	}
	void make_fail(){
		static int h[N*M+10];
		int head=1,tail=0;
		for (int i=0;i<26;i++)	if (trie[root][i])	h[++tail]=trie[root][i];
		for (;head<=tail;head++){
			int Now=h[head];
			End[Now]|=End[fail[Now]];
			for (int i=0;i<26;i++){
				if (trie[Now][i]){
					int son=trie[Now][i];
					fail[son]=trie[fail[Now]][i];
					h[++tail]=son;
				}else	trie[Now][i]=trie[fail[Now]][i];
			}
		}
	}
}AC;//Aho-Corasick automaton
int mlt(int a,int b){
	int res=1;
	for (;b;b>>=1,a=1ll*a*a%Mod)	if (b&1)	res=1ll*res*a%Mod;
	return res;
}
int f[N+10][N*M+10];
int main(){
	int n=read(),m=read();
	for (int i=1;i<=n;i++){
		static char s[N+10];
		scanf("%s",s);
		AC.insert(s);
	}AC.make_fail();
	f[0][0]=1;
	for (int i=0;i<m;i++){
		for (int j=0;j<AC.tot;j++){
			if (!f[i][j])	continue;
			for (int k=0;k<26;k++){
				int son=AC.trie[j][k];
				if (AC.End[son])	continue;
				f[i+1][son]=(f[i+1][son]+f[i][j])%Mod;
			}
		}
	}
	int Ans=mlt(26,m);
	for (int i=0;i<=AC.tot;i++)	Ans=(Ans-f[m][i])%Mod;
	printf("%d\n",(Ans+Mod)%Mod);
	return 0;
}
posted @ 2019-03-06 20:35  Wolfycz  阅读(212)  评论(0编辑  收藏  举报