BZOJ 1030 文本生成器

很老的题目了,很早以前学AC自动机的时候就A过一次

今天算是复习啦

我们可以把问题转化成一个给定字符串都没出现的字符串有多少个

我们建立AC自动机,设dp[i][j]表示走了i步当前在j节点上

在DP的过程中不转移单词节点即可

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn=6010;
const int mod=10007;
int n,m,cnt=1,ans;
char s[maxn];
int t[maxn][26];
int fail[maxn];
int dp[102][maxn];
bool end[maxn];
queue<int>Q;

void insert(){
	scanf("%s",s+1);
	int len=strlen(s+1),now=1;
	for(int i=1;i<=len;++i){
		int id=s[i]-'A';
		if(!t[now][id])t[now][id]=++cnt;
		now=t[now][id];
	}end[now]=true;
}
void build_fail(){
	Q.push(1);fail[1]=0;
	while(!Q.empty()){
		int u=Q.front();Q.pop();
		end[u]|=end[fail[u]];
		for(int i=0;i<26;++i){
			int k=fail[u];
			while(k&&!t[k][i])k=fail[k];
			if(t[u][i]){
				fail[t[u][i]]=k?t[k][i]:1;
				Q.push(t[u][i]);
			}else t[u][i]=k?t[k][i]:1;
		}
	}return;
}
void Get_DP(){
	dp[0][1]=1;
	for(int i=0;i<m;++i){
		for(int j=1;j<=cnt;++j){
			if(!dp[i][j])continue;
			for(int k=0;k<26;++k){
				int now=t[j][k];
				if(end[now])continue;
				dp[i+1][now]+=dp[i][j];
				if(dp[i+1][now]>=mod)dp[i+1][now]-=mod;
			}
		}
	}return;
}
int pow_mod(int v,int p){
	int tmp=1;
	while(p){
		if(p&1)tmp=tmp*v%mod;
		v=v*v%mod;p>>=1;
	}return tmp;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)insert();
	build_fail();
	Get_DP();
	ans=0;
	for(int i=1;i<=cnt;++i){
		ans=ans+dp[m][i];
		if(ans>=mod)ans-=mod;
	}
	ans=pow_mod(26,m)-ans;
	ans=(ans+mod)%mod;
	printf("%d
",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/joyouth/p/5367131.html