zoukankan      html  css  js  c++  java
  • Wireless Password HDU

    Wireless Password HDU - 2825(AC自动机,状压DP)

    传送门

    题意:给m种子串,要求长度为n的构造串中至少有k种串,求方案数。

    题解:将m个串放入字典树中,然后在字典树dfs搜索所有情况,搜索到底时要判断种类是否超过k个,这里用状态压缩存储,在加记忆化即可。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<vector>
    using namespace std;
    #define ll long long
    int n,m,ma[107][26],cnt,tk;
    int fail[107];
    int vis[107];
    ll dp[107][26][1027];
    int er[107];
    const int mod=20090717;
    string s;
    void up(string s,int k){
    	int now=0;
    	for(int i=0;i<s.length();i++){
    		if(ma[now][s[i]-'a']==0){
    			ma[now][s[i]-'a']=++cnt;
    		}
    		now=ma[now][s[i]-'a'];
    	}
    	vis[now]|=er[k];
    }
    void fgo(){
    	queue<int>sa;
    	for(int i=0;i<=25;i++){
    		if(ma[0][i]){
    			sa.push(ma[0][i]);
    			fail[ma[0][i]]=0;
    		}
    	}
    	while(!sa.empty()){
    		int now=sa.front();
    		sa.pop();
    		for(int i=0;i<=25;i++){
    			if(ma[now][i]){
    				sa.push(ma[now][i]);
    				fail[ma[now][i]]=ma[fail[now]][i];
    			}
    			else{
    				ma[now][i]=ma[fail[now]][i];
    			}
    		}
    		vis[now]|=vis[fail[now]];
    	}
    }
    ll dfs(int p,int h,int k){
    	if(h==n){
    		int cnt=0;
    		for(int i=0;i<m;i++){
    			if(k&er[i])cnt++;
    		}
    		if(cnt>=tk){
    			return 1;
    		}
    		else{
    			return 0;
    		}
    	}
    	if(dp[p][h][k]!=-1){
    		return dp[p][h][k];
    	}
    	ll ans=0;
    	for(int i=0;i<=25;i++){
    		int now=k;
    		now|=vis[ma[p][i]];
    		ans+=dfs(ma[p][i],h+1,now);
    		ans%=mod;
    	}
    	return dp[p][h][k]=ans;
    }
    void init(){
    	memset(vis,0,sizeof(vis));
    	memset(fail,0,sizeof(fail));
    	memset(dp,-1,sizeof(dp));
    	memset(ma,0,sizeof(ma));
    	cnt=0;
    }
    int main(){
    	er[0]=1;
    	for(int i=1;i<=10;i++){
    		er[i]=er[i-1]*2;
    	}
    	while(1){
    		init();
    		scanf("%d%d%d",&n,&m,&tk);
    		if(n==0&&m==0&&tk==0)break;
    		for(int i=0;i<m;i++){
    			cin>>s;
    			up(s,i);
    		}
    		fgo();
    		printf("%lld
    ",dfs(0,0,0));
    	}
    }
    
  • 相关阅读:
    linux每日命令(29): chown命令
    linux每日命令(28): charp命令
    linux每日命令(27): chmod命令
    linux每日命令(26):Linux文件属性详解
    linux每日命令(25): linux文件类型与扩展名
    linux每日命令(24): linux目录结构
    linux每日命令(23): find命令之xargs
    linux每日命令(22): find命令参数详解
    2017年12月31日
    Python使用otp实现二步验证
  • 原文地址:https://www.cnblogs.com/whitelily/p/14044271.html
Copyright © 2011-2022 走看看