zoukankan      html  css  js  c++  java
  • [题解]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神%%%

  • 相关阅读:
    js中常用的算法排序
    bootstrap Table的使用方法
    js中的继承
    js函数的节流与防抖
    along.js
    Vue组件通讯
    前端性能优化
    Vue路由学习心得
    Vue 2.0 路由全局守卫
    【前端】自适应布局方法总结
  • 原文地址:https://www.cnblogs.com/czy--blog/p/13877806.html
Copyright © 2011-2022 走看看