zoukankan      html  css  js  c++  java
  • 题解 LuoguP4052文本生成器(AC自动机 + DP)

    题意

    https://www.luogu.com.cn/problem/P4052

    算法

    AC自动机上的套路DP

    思路

    正面处理困难,于是考虑容斥,求不合法的方案数。考虑使用AC自动机,则原问题转化为:求使这(m)个字符串都匹配不上的字符串的个数。所以,匹配过程中经过的点,其(fail)链上的节点(包括本身)都不能有结束节点。

    (dp(i,j))表示从根节点开始走(i)步到(j)号节点的方案数,状态转移方程为:

    [dp(i, j) = sum_{!t[k].num}dp(i - 1, k){ (t[k].num表示k号节点的fail链上是否有结束节点)} ]

    代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 5e4 + 10,mode = 1e4 + 7;
    int n,f[6010][6010],m,ans;
    string a;
    
    struct AC{
    	int cnt;
    	struct Tree{
    		int num,fail;
    		int ch[30];
    	}t[maxn];
    	AC(){cnt = 0;}
    
    	void build(string s){
    		int len = s.size(); int now = 0;
    		for(int i = 0; i < len; ++ i){
    			int c = s[i] - 'A';
    			if(!t[now].ch[c]) t[now].ch[c] = ++cnt;
    			now = t[now].ch[c];
    		}
    		t[now].num = 1;
    	}
    
    	void get_fail(){
    		queue<int> q;
    		for(int i = 0; i < 26; ++ i)
    			if(t[0].ch[i]){
    				t[t[0].ch[i]].fail = 0;
    				q.push(t[0].ch[i]);
    			}
    		while(!q.empty()){
    			int u = q.front(); q.pop();
    			for(int i = 0; i < 26; ++ i){
    				int v = t[u].ch[i];
    				if(v){
    					t[v].fail = t[t[u].fail].ch[i];
    					q.push(v);
    					t[v].num |= t[t[v].fail].num;
    				}
    				else t[u].ch[i] = t[t[u].fail].ch[i];
    			}
    		}
    	}
    
    	void DP(){
    		f[0][0] = 1;
    		for(int i = 1; i <= m; ++ i)
    			for(int j = 0; j <= cnt; ++ j)
    				if(!t[j].num){
    					for(int k = 0; k < 26; ++ k)
    						f[i][t[j].ch[k]] = (f[i][t[j].ch[k]] + f[i - 1][j]) % mode;
    				}
    		for(int i = 0; i <= cnt; ++ i)
    			if(!t[i].num) ans += f[m][i], ans %= mode;
    	}
    }ac;
    
    int ksm(int a, int b){  //递归版本快速幂
    	if(b == 1) return a;
    	if(b == 0) return 1;
    	if(b & 1) return ((a * ksm(a, b / 2)) % mode * ksm(a, b / 2)) % mode;
    	else return (ksm(a, b / 2) * ksm(a, b / 2)) % mode;
    }
    
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> m;
    	for(int i = 1; i <= n; ++ i){
    		cin >> a;
    		ac.build(a);
    	}
    	ac.get_fail(); ac.DP();
    	cout << (ksm(26, m) - ans + mode) % mode << endl;
    	return 0;
    }
    
  • 相关阅读:
    Mysql存储过程和函数
    python反编译chm文件并生成pdf文件
    python转换html到pdf文件
    python获取系统开机时间
    OpenSL ES: 利用OpenSL ES实现录音功能
    android: 根据文件uri 获取文件名
    Java: InputStream转化为byte数组
    Linux: 查看二进制文件
    Vim: 回到上次编辑的位置
    LayoutInflate: Avoid passing null as the view root
  • 原文地址:https://www.cnblogs.com/whenc/p/13808920.html
Copyright © 2011-2022 走看看