zoukankan      html  css  js  c++  java
  • 洛谷P4052 [JSOI2007]文本生成器 (AC自动机+ dp)

    题目链接:https://www.luogu.com.cn/problem/P4052

    套路题,利用 (fail) 指针转移 (dp)

    首先是正难则反,计算不包含可读单词的方案数
    (dp[i][j]) 表示长度为 (i) 的文本,当前在 (j) 节点,不经过单词节点的方案数

    直接在 (trie) 图上转移即可

    注意:如果一个节点单词的后缀是单词节点,那这个节点也不能经过

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 10010; 
    const int M = 10007;
    
    int n, m, rt = 0, tot = 0; 
    ll ans = 0;
    struct Node{
    	int son[30], sz, fail;
    }t[maxn];
    
    int dp[110][maxn];
    
    char s[maxn];
    
    void insert(){
    	int p = rt;
    	int len = strlen(s);
    	for(int i = 0 ; i < len ; ++i){
    		if(!t[p].son[s[i] - 'A']){
    			t[p].son[s[i] - 'A'] = ++tot;
    		}
    		p = t[p].son[s[i] - 'A'];
    	} 
    	t[p].sz = 1;
    }
    
    queue<int> q; 
    void build(){
    	t[rt].fail = rt;
    	for(int i = 0 ; i <= 25 ; ++i){
    		if(t[rt].son[i]) q.push(t[rt].son[i]);
    	}
    	
    	while(!q.empty()){
    		int u = q.front(); q.pop();
    		t[u].sz |= t[t[u].fail].sz;
    		for(int i = 0 ; i <= 25 ; ++i){
    			if(t[u].son[i]){
    				t[t[u].son[i]].fail = t[t[u].fail].son[i];
    				q.push(t[u].son[i]);
    			} else{
    				t[u].son[i] = t[t[u].fail].son[i];
    			}
    		}
    	}
    }
    
    int qsm(int i, int po){
    	int res = 1;
    	while(po){
    		if(po & 1) res = 1ll * res * i % M;
    		po >>= 1;
    		i = 1ll * i * i % M;
    	}
    	return res;
    }
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	n = read(), m = read();
    	for(int i = 1 ; i <= n ; ++i){
    		scanf("%s", s);
    		insert();
    	}
    	
    	build();
    	
    	dp[0][0] = 1;
    	for(int i = 1 ; i <= m ; ++i){
    		for(int j = 0 ; j <= tot ; ++j){
    			for(int k = 0 ; k <= 25 ; ++k){
    				if(!t[t[j].son[k]].sz) dp[i][t[j].son[k]] = (dp[i][t[j].son[k]] + dp[i - 1][j]) % M;
    			}
    		}
    	}
    	
    	int ans = 0;
    	for(int i = 0 ; i <= tot ; ++i){
    		ans = (ans + dp[m][i]) % M;
    	}
    	
    	printf("%d
    ", ((qsm(26, m) - ans) % M + M) % M);
    	
    	return 0;
    }
    
  • 相关阅读:
    JAVA中的SimpleDateFormat yyyy和YYYY的区别
    Mysql的MVCC
    SELECT语句中的for update的用法(锁的运用)
    今天简单说一下cdc 的使用
    sqlserver cdc用法
    JAVA | Java对象的内存分配过程是如何保证线程安全的?
    物联网(莹石云)WIFI一键配置原理分析(zz)
    Dell xps 13 9350待机时总是关机的处理方法
    Vue系列:在vux的popup组件中使用百度地图遇到显示不全的问题
    如何通过百度地图将经纬度转换为地址信息
  • 原文地址:https://www.cnblogs.com/tuchen/p/14191213.html
Copyright © 2011-2022 走看看