zoukankan      html  css  js  c++  java
  • HDU-2825 Wireless Password(AC自动机+状压DP)

    题目大意:给一系列字符串,用小写字母构造出长度为n的至少包含k个字符串的字符串,求能构造出的个数。

    题目分析:在AC自动机上走n步,至少经过k个单词节点,求有多少种走法。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<queue>
    # include<cstring>
    # include<algorithm>
    using namespace std;
    
    typedef long long LL;
    
    const int mod=20090717;
    
    int ch[105][26];
    int cnt,fail[105];
    int val[105];
    
    void init()
    {
    	cnt=0;
    	memset(ch,-1,sizeof(ch));
    	memset(val,0,sizeof(val));
    }
    
    int idx(char x)
    {
    	return x-'a';
    }
    
    void insert(char *s,int k)
    {
    	int len=strlen(s);
    	int r=0;
    	for(int i=0;i<len;++i){
    		int c=idx(s[i]);
    		if(ch[r][c]==-1) ch[r][c]=++cnt;
    		r=ch[r][c];
    	}
    	val[r]|=(1<<k);
    }
    
    void getFail()
    {
    	queue<int>q;
    	fail[0]=0;
    	for(int i=0;i<26;++i){
    		if(ch[0][i]==-1)
    			ch[0][i]=0;
    		else{
    			fail[ch[0][i]]=0;
    			q.push(ch[0][i]);
    		}
    	}
    	while(!q.empty())
    	{
    		int u=q.front();
    		q.pop();
    		val[u]|=val[fail[u]];
    		for(int i=0;i<26;++i){
    			if(ch[u][i]==-1)
    				ch[u][i]=ch[fail[u]][i];
    			else{
    				fail[ch[u][i]]=ch[fail[u]][i];
    				q.push(ch[u][i]);
    			}
    		}
    	}
    }
    
    char word[15];
    int dp[2][105][1<<10];
    
    int getDigt(int x,int n)
    {
    	int count=0;
    	for(int i=0;i<n;++i)
    		if(x&(1<<i)) ++count;
    	return count;
    }
    
    int DP(int n,int m,int k)
    {
    	memset(dp,0,sizeof(dp));
    	int cur=1;
    	dp[0][0][0]=1;
    	for(int i=0;i<n;++i){
    		memset(dp[cur],0,sizeof(dp[cur]));
    		for(int j=0;j<=cnt;++j){
    			for(int s=0;s<(1<<m);++s) if(dp[cur^1][j][s]){	///不加if语句会超时
    				for(int c=0;c<26;++c){
    					int &nxt=dp[cur][ch[j][c]][s|val[ch[j][c]]];
    					nxt=(nxt+dp[cur^1][j][s])%mod;
    				}
    			}
    		}
    		cur^=1;
    	}
    	int ans=0;
    	for(int i=0;i<(1<<m);++i) if(getDigt(i,m)>=k){
    		for(int j=0;j<=cnt;++j)
    			ans=(ans+dp[cur^1][j][i])%mod;
    	}
    	return ans;
    }
    
    int main()
    {
    	int n,m,k;
    	while(scanf("%d%d%d",&n,&m,&k)&&(n||m||k))
    	{
    		init();
    		for(int i=0;i<m;++i){
    			scanf("%s",word);
    			insert(word,i);
    		}
    		getFail();
    		printf("%d
    ",DP(n,m,k));
    	}
    	return 0;
    }
    
  • 相关阅读:
    23. Sum Root to Leaf Numbers
    22. Surrounded Regions
    21. Clone Graph
    19. Palindrome Partitioning && Palindrome Partitioning II (回文分割)
    18. Word Ladder && Word Ladder II
    14. Reverse Linked List II
    20. Candy && Gas Station
    16. Copy List with Random Pointer
    ubuntu 下建立桌面快捷方式
    java基础篇-jar打包
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5998330.html
Copyright © 2011-2022 走看看