zoukankan      html  css  js  c++  java
  • UVa 1076 Password Suspects (AC自动机+状压dp)

    题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3517

    生成文本,要求含或不含某些连续子串的题目一般是 (AC) 自动机 (+) (dp) 的套路

    (dp[u][len][st]) 表示当前在状态图的节点 (u),当前生成的文本长度为 (len),含子串的状态为 (st) 时的方案数

    注意: 因为一个单词节点可能是多个单词的结尾((last) 函数的含义),所以在计算失配函数 (fail) 指针时要同时更新当前节点的 (last)(val)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 405;
    
    int n, m; 
    int ok;
    char s[20];
    
    int ch[maxn][30], f[maxn], val[maxn], last[maxn];
    ll dp[maxn][27][1<<11];
    
    int sz = 0, rt = 0;
    
    void init(){
    	sz = 0;
    	ok = (1<<m)-1;
    	memset(ch, 0, sizeof(ch));
    	memset(val, 0, sizeof(val));
    	memset(f, 0, sizeof(f));
    	memset(last, 0, sizeof(last));
    	memset(dp, -1, sizeof(dp));
    }
    
    int idx(char c){
    	return c - 'a';
    }
    
    void insert(int num){
    	int p = rt, len = strlen(s);
    	for(int i = 0 ; i < len ; ++i){
    		int c = idx(s[i]);
    		if(!ch[p][c]) {
    			++sz;
    			val[sz] = 0;
    			ch[p][c] = sz;
    		}
    		p = ch[p][c];
    	}
    	val[p] |= (1<<num);
    }
    
    void getfail(){
    	queue<int> q;
    	f[0] = 0;
    	
    	for(int i = 0 ; i < 26 ; ++i){
    		int u = ch[0][i];
    		if(u) {
    			f[u] = 0; q.push(u); last[u] = 0;
    		}
    	}
    	
    	while(!q.empty()){
    		int r = q.front(); q.pop();
    		for(int i = 0 ; i < 26 ; ++i){
    			int u = ch[r][i];
    			if(!u) {
    				ch[r][i] = ch[f[r]][i];
    				continue;
    			}
    			q.push(u);
    			int v = f[r];
    			while(v && !ch[v][i]) v = f[v];
    			f[u] = ch[v][i];
    			last[u] = val[f[u]] ? f[u] : last[f[u]];
    			val[u] |= val[last[u]]; //***
    		}
    	}
    }
    
    ll dfs(int u, int len, int st){
    	if(dp[u][len][st] != -1) return dp[u][len][st];
    	if(len == n) return dp[u][len][st] = (st == ok);
    	
    	dp[u][len][st] = 0;
    	for(int i = 0 ; i < 26 ; ++i){
    		dp[u][len][st] += dfs(ch[u][i], len+1, st|val[ch[u][i]]);
    	}
    	return dp[u][len][st];
    }
    
    char ss[110];
    int l = 0;
    
    void print(int u, int len, int st){
    	if(len == n){
    		printf("%s
    ", ss+1);
    		return;
    	}
    	
    	for(int i = 0 ; i < 26 ; ++i){
    		if(dp[ch[u][i]][len+1][st|val[ch[u][i]]]){
    			ss[len+1] = i+'a';
    			print(ch[u][i], len+1, st|val[ch[u][i]]);
    		}
    	}
    }
    
    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(){
    //	freopen("ans.out", "w", stdout);
    	int kase = 0;
    	while(scanf("%d%d", &n, &m) == 2 && n){
    		memset(ss, 0, sizeof(ss));
    		init();
    		
    		for(int i = 0 ; i < m ; ++i){
    			scanf("%s", s);
    			insert(i);
    		}
    		
    		getfail();
    		
    		ll ans = dfs(0, 0, 0);
    		printf("Case %d: ", ++kase);
    		printf("%lld suspects
    ", ans);
    		
    		if(ans <= 42){
    			print(0, 0, 0);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    js 宿主对象的属性和方法总结
    java学习路线
    (转)前端学习路线
    第11章 PADS功能使用技巧(2)-最全面
    第11章 PADS功能使用技巧(1)-最全面
    可控硅工作原理及参数详解
    光耦继电器工作原理与参数详解
    EEPROM工作原理透彻详解
    晶振工作原理及参数详解(最透彻)
    逻辑门电路详解1(最透彻)
  • 原文地址:https://www.cnblogs.com/tuchen/p/15230621.html
Copyright © 2011-2022 走看看