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

[不稳定的传送门]

Solution

考虑算出所有不包含给定字符串的方案数,在用总数减去就行了

f[i][j]表示到第i个字符串,当前停在自动机上j点的方案数

Code

 

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 6010
using namespace std;

char s[110];
const int mo=10007;
int n,m,f[110][N],T[N][27],fail[N],tot=1,mark[N],q[N],sum=1,Ans;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void Insert(){
	scanf("%s\n",&s);
	int len=strlen(s),now=1;
	for(int i=0;i<len;++i){
		if(!T[now][s[i]-64]) T[now][s[i]-64]=++tot;
		now=T[now][s[i]-64];
	}
	mark[now]=1;
}

void getfail(){
	for(int i=1;i<=26;++i) T[0][i]=1;
	int k,now,h=0,t=0;q[++t]=1;
	while(h<t){
		mark[now=q[++h]]|=mark[fail[now]];
		for(int i=1;i<=26;++i)
			if(T[now][i]){
				k=fail[now];
				while(!T[k][i]) k=fail[k];
				fail[q[++t]=T[now][i]]=T[k][i];
			}
	}
}

int main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i) Insert();
	getfail();
	f[0][1]=1;
	for(int i=0;i<m;++i)
		for(int j=1;j<=tot;++j)
			for(int k=1;k<=26;++k)
				if(!mark[j]){
					int now=j;
					while(!T[now][k]) now=fail[now];
					now=T[now][k];
					(f[i+1][now]+=f[i][j])%=mo;
				}
	for(int i=1;i<=m;++i) sum=sum*26%mo;
	for(int i=0;i<=tot;++i) if(!mark[i]) Ans=(Ans+f[m][i])%mo;
	printf("%d\n",(sum-Ans+mo)%mo);
	return 0;
}

 

posted @ 2018-04-23 20:57  void_f  阅读(133)  评论(0编辑  收藏  举报