Loading

题解 lg4052 [JSOI2007]文本生成器--AC自动机

题目链接

这是一道十分经典的AC自动机+dp的题目

大意

求长度为m、字符集为大写字母、包含至少一个模式串的所有字符串的数目,对\(1e4+7\)取模

思路

看到这种匹配类的东西可以考虑AC自动机。但直接求出答案比较复杂,我们考虑转换为其补集即不包含任何任何一个模式串的字符串数目.

对模式串建立AC自动机,当节点为 危险节点 ,即结束节点或者其祖先为结束节点(因为一个单词的后缀是一个可读单词时,这个单词一定可读的)都不可以,所以对于后一种有以下代码

ed[trie[x][i]]|=ed[fail[trie[x][i]]];

假设 \(f_{i,j}\) 表示已经匹配到\(trie\)图上的节点\(i\),长度为 \(j\) 的不合法字符串个数,我们枚举接下来的字符,即可实现转移,有以下dp方程式

\[f_{trie_{i,k},j}(trie_{i,k}\notin ed)=\sum_{i\notin ed} f_{trie_{i},j-1} \]

意思就是说将这个非危险节点的答案转移到它的非危险的儿子上去.

注意(我掉的坑)

  1. \(Trie\)的大小为字符串总大小×字符集大小

    不会吧不会吧,真有人这么傻掉这个坑吗

    就是我啊

  2. 根节点在AC自动机中有它特有的含义,仔细思考

代码

#include<bits/stdc++.h>
using namespace std;
int const MOD=1e4+7;
int n,m,sum;
int f[6001][1010];
char s[2000];
struct AC_Automaton{
	int trie[10010][30],fail[60010],ed[60010];
	int tot;
	queue<int>q;
	void insert(){
		int len=strlen(s+1);int now=0;
		for(int i=1;i<=len;i++){
			int x=s[i]-'A';
			if(!trie[now][x]){trie[now][x]=++tot;}
			now=trie[now][x];
		}
		ed[now]=1;
	}
	void getfail(){
		for(int i=0;i<26;i++){
			if(trie[0][i]){
				fail[trie[0][i]]=0;
				q.push(trie[0][i]);
			}
		}
		while(!q.empty()){
			int x=q.front();q.pop();
			for(int i=0;i<26;i++){
				if(trie[x][i]){
					fail[trie[x][i]]=trie[fail[x]][i];
					q.push(trie[x][i]);
					ed[trie[x][i]]|=ed[fail[trie[x][i]]];
				}else{
					trie[x][i]=trie[fail[x]][i];
				}
			}
		}
	}
}ACA;
int qpow(int x,int k){
	int ans=1;
	while(k){
		if(k&1)ans=(ans*x)%MOD;
		k>>=1;
		x=x*x%MOD;
	}
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		ACA.insert();
	}
	ACA.getfail();
	for(int i=0;i<26;i++){
		if(!ACA.ed[ACA.trie[0][i]])f[ACA.trie[0][i]][1]+=1;
	}
	for(int i=2;i<=m;i++){
		for(int j=0;j<=ACA.tot;j++){
			if(!ACA.ed[j]){
				for(int k=0;k<26;k++){
					if(!ACA.ed[ACA.trie[j][k]])f[ACA.trie[j][k]][i]=(f[ACA.trie[j][k]][i]+f[j][i-1])%MOD;
				}
			}
		}
	}
	for(int j=0;j<=ACA.tot;j++)if(!ACA.ed[j])sum=(sum+f[j][m])%MOD;
	printf("%d\n",(qpow(26,m)-sum+MOD)%MOD);
	return 0;
}
posted @ 2020-10-27 19:18  fpjo  阅读(90)  评论(0编辑  收藏  举报