• BZOJ1559: [JSOI2009]密码


    BZOJ1559: [JSOI2009]密码

    https://lydsy.com/JudgeOnline/problem.php?id=1559

    分析:

    • (f[i][j][s])表示已经有了(i)位, 在ac自动机上(j)号结点上,出现子串状态为(s)的方案数。
    • 输出方案也好做,记忆化+标记,然后直接搜,这样复杂度就等于答案串个数乘串长了。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    #define N 105
    char w[25];
    int ch[N][26],cnt=1,fail[N],K,n,sta[N],Q[N],mask;
    ll f[30][N][1050];
    char is[30][N][1050];
    char ans[N];
    void insert(int id) {
    	int i,p=1,m=strlen(w+1);
    	for(i=1;i<=m;i++) {
    		int &k=ch[p][w[i]-'a'];
    		if(!k) k=++cnt;
    		p=k;
    	}
    	sta[p]|=(1<<(id-1));
    }
    void build() {
    	int i,p;
    	for(i=0;i<26;i++) ch[0][i]=1;
    	int l=0,r=0; Q[r++]=1;
    	while(l<r) {
    		p=Q[l++]; sta[p]|=sta[fail[p]];
    		for(i=0;i<26;i++) {
    			if(ch[p][i]) fail[ch[p][i]]=ch[fail[p]][i],Q[r++]=ch[p][i];
    			else ch[p][i]=ch[fail[p]][i];
    		}
    	}
    }
    int dfs(int nd,int p,int st) {
    	if(is[nd][p][st]!=-1) return is[nd][p][st];
    	if(nd==n) {
    		if(st==mask) return is[nd][p][st]=1;
    		else return is[nd][p][st]=0;
    	}
    	int re=0;
    	int i;
    	for(i=0;i<26;i++) re|=dfs(nd+1,ch[p][i],st|sta[ch[p][i]]);
    	return is[nd][p][st]=re;
    }
    void solve(int nd,int p,int st) {
    	if(is[nd][p][st]!=1) return ;
    	int i;
    	if(nd==n) {
    		if(st==mask) printf("%s
    ",ans+1);
    		return;
    	}
    	for(i=0;i<26;i++) {
    		if(is[nd+1][ch[p][i]][st|sta[ch[p][i]]]==1) {
    			//printf("%d:%c,f=%lld
    ",nd+1,i+'a',f[nd+1][ch[p][i]][st|sta[ch[p][i]]]);
    			ans[nd+1]=i+'a';
    			solve(nd+1,ch[p][i],st|sta[ch[p][i]]);
    		}
    	}
    }
    int main() {
    	//freopen("fire.in","r",stdin);
    	//freopen("fire.out","w",stdout);
    	scanf("%d%d",&n,&K);
    	int i;
    	mask=(1<<K)-1;
    	for(i=1;i<=K;i++) {
    		scanf("%s",w+1);
    		insert(i);
    	}
    	build();
    	f[0][1][0]=1;
    	int j,k,l;
    	for(i=0;i<n;i++) {
    		for(j=1;j<=cnt;j++) {
    			for(k=0;k<=mask;k++) if(f[i][j][k]) {
    				for(l=0;l<26;l++) {
    					int p=ch[j][l];
    					f[i+1][p][k|sta[p]]+=f[i][j][k];
    				}
    			}
    		}
    	}
    	ll ans=0;
    	for(i=1;i<=cnt;i++) ans+=f[n][i][mask];
    	printf("%lld
    ",ans);
    	if(ans>42) return 0;
    	memset(is,-1,sizeof(is));
    	dfs(0,1,0);
    	solve(0,1,0);
    }
    
  • 相关阅读:
    如何读入位图(五)
    如何读入位图(四)
    绘制正弦曲线
    图像灰度均衡
    色彩填充及使用
    彩色扇形
    如何读入位图(三)
    ARCGIS FOR SILVERLIGHT Layer
    sqlserver2008多数据库操作(未完)
    SQLSERVER 2008 远程无法连接问题
  • 原文地址:https://www.cnblogs.com/suika/p/10229768.html
Copyright © 2020-2023  润新知