[题解]lgP4052文本生成器

[题解]lgP4052文本生成器

问题分析

​ 这个题是要求多模式串的匹配,所以自然的想到AC自动机,但是题目中说"至少含有一个认识的单词"并不好处理,所以我们不妨求出所有不存在认识的单词的文本串,再用总的可能情况减去不含有认识单词的文本串数量即可.

​ 既然要求不存在认识单词的文本串,那么匹配过程中肯定不能拓展到存在有单词的节点(可以称之为结束节点)(在程序中的标志是trie[now].cnt != 0,意思就是如果扩展到当前节点,那么就存在有认识的单词,可以结合cnt的定义来理解,参见AC自动机博客),所以一切可以到达结束节点的方案都是存在有认识的单词的,所以在求\(fail\)指针的时候可以进行标记.

​ 在统计答案的时候要用\(dp\),设\(dp[i][j]\)表示从根节点走\(i\)步到达\(j\)节点的方案数,转移方程:

\(dp[i][j] = Σ_{t[k].cnt == 0}{dp[i - 1][k]}\)

代码如下

#include <bits/stdc++.h>
using namespace std;
int n,m;
struct node{
	int fail;
	int cnt;
	int next[62];
}trie[1000010 * 3];
char s[6100];
int tot;
void build(int id,char s[]){
	int len = strlen(s);
	for(int i = 0;i < len;i++){
		int tmp = s[i] - 'A';
		if(trie[id].next[tmp] == 0){
			trie[id].next[tmp] = ++tot;
		}
		id = trie[id].next[tmp];
	}
	trie[id].cnt = 1;
}
void build_fail(int id){
	queue < int > q;
	while(!q.empty())q.pop();
	for(int i = 0;i < 26;i++){
		if(trie[id].next[i] != 0){
			trie[trie[id].next[i]].fail = id;
			q.push(trie[id].next[i]);
		}
	}
	while(!q.empty()){
		int x = q.front();
		q.pop();
		for(int i = 0;i < 26;i++){
			if(trie[x].next[i] == 0){
				trie[x].next[i] = trie[trie[x].fail].next[i];
				continue;
			}
			else {

				trie[trie[x].next[i]].fail = trie[trie[x].fail].next[i];
				q.push(trie[x].next[i]);
				trie[trie[x].next[i]].cnt += trie[trie[trie[x].next[i]].fail].cnt;
			}
		}
	}
}
int f[6110][6110];
int ans;
void dp(){
	f[0][0] = 1;
	for(int i = 1;i <= m;i++){
		for(int j = 0;j <= tot;j++){
			if(!trie[j].cnt){
				for(int k = 0;k < 26;k++){
					f[i][trie[j].next[k]] = (f[i][trie[j].next[k]] + f[i - 1][j]) % 10007;
				}
			}
		}
	}
	for(int i = 0;i <= tot;++i){
		if(!trie[i].cnt){
			ans += f[m][i];
			ans %= 10007;
		}
	}
}
int pow(int x,int t){
	if(t == 1)return x;
	if(t == 0)return 1;
	if(t & 1)return ((x * pow(x,t >> 1)) % 10007 * pow(x,t >> 1)) % 10007;
	else return (pow(x,t >> 1) * pow(x,t >> 1)) % 10007;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++){
		cin>>s;
		build(0,s);
	}
	build_fail(0);
	dp();
	cout<<(pow(26,m) - ans + 10007) % 10007<<endl;
	return 0;
}

参考了Wen佬的博客

Wen神%%%

posted @ 2020-10-26 12:12  czyczy  阅读(124)  评论(0编辑  收藏  举报