zoukankan      html  css  js  c++  java
  • bzoj3864-hdu4899-Hero meet devil

    题目

    给出一个由AGTC组成的字符串(S),长度为(n),对于每个(iin [0,n]),问有多少个长度为(m),仅含有AGTC的字符串(T)使得(S)(T)的最长公共子串长度为(i)((nle 15,mle 1000))

    Sample Input

    GTC
    10
    

    Sample Output

    1
    22783
    528340
    497452
    

    分析

    这是一个经典的问题,解法称为dp套dp。这一类问题要求解的是有多少种输入可以使得一个dp的最终结果为一个特定值。在这道题中的表现就是,求有多少个字符串(T)使得求解lcs的dp的最终结果为(i)。对于这类问题,一般的方法是,对于内部dp(这里的lcs)观察它的求解过程,把dp的过程状态压缩,放在外层dp中。

    观察lcs的求解过程:

    [lcs[i][j]=max egin{cases} lcs[i-1][j-1]+1 & ext{if t[i]=s[j]} \ lcs[i-1][j] \ lcs[i][j-1] end{cases} ]

    注意到这个转移的过程中,一行只和上一行有关,而且同一行中相邻两位最多差1,所以我们可以把一行差分,状态压缩。即令(f[i][j])表示枚举到第(i)个字符,这时候内层dp状态为(j)的情况数。那么可以直接得到计算方程:

    [egin{aligned} f[i][trans(j,k)]+=f[i-1][j] end{aligned} ]

    其中(trans(j,k))表示从(j)状态加一个字母(k)转移到的状态。比如说,(s= ext{'ACT'},j=010),由于差分过,所以原来的状态是(011),即当前的匹配是C。接下来加入一个T,那么状态会变成(012),压缩后变为(011)。注意到这个trans是固定的,所以可以每次预处理。

    预处理复杂度为(O(kn2^n)),外层dp复杂度为(O(km2^n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long giant;
    const int maxn=15;
    const int maxm=1<<maxn;
    const int maxa=1e3+1;
    const int q=1e9+7;
    const char sta[]=" ACGT";
    char s[maxn+1];
    int t[maxm][5],f[maxa+2][maxm+2],ans[maxn+2],n,a[maxn+2];
    int change(char c) {
    	for (int i=1;i<=4;++i) if (c==sta[i]) return i;
    	return 5;
    }
    void add(int &x,int y) {
    	x+=y;
    	if (x>q) x-=q;
    }
    int count(int x) {
    	int ret=0;
    	for (int i=0;i<maxn;++i) ret+=((x>>i)&1);
    	return ret;
    }
    int tf[2][maxn+2];
    int trans(int sit,int c) {
    	memset(tf,0,sizeof tf);
    	for (int i=0;i<n;++i) tf[0][i+1]=tf[0][i]+((sit>>i)&1);
    	for (int i=1;i<=n;++i) {
    		int tmp=0;
    		if (a[i]==c) tmp=max(tmp,tf[0][i-1]+1);
    		tmp=max(tmp,max(tf[0][i],tf[1][i-1]));
    		tf[1][i]=tmp;
    	}
    	int ret=0;
    	for (int i=0;i<n;++i) ret+=(1<<i)*(tf[1][i+1]-tf[1][i]);
    	return ret;
    }
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    	freopen("my.out","w",stdout);
    #endif
    	int T;
    	scanf("%d",&T);
    	while (T--) {
    		memset(ans,0,sizeof ans);
    		memset(f,0,sizeof f);
    		memset(a,0,sizeof a);
    		scanf("%s",s+1);
    		n=strlen(s+1);
    		int m;
    		scanf("%d",&m);
    		f[0][0]=1;
    		for (int i=1;i<=n;++i) a[i]=change(s[i]);
    		for (int j=0;j<(1<<n);++j) for (int k=1;k<=4;++k) t[j][k]=trans(j,k);
    		for (int i=1;i<=m;++i) {
    			for (int j=0;j<(1<<n);++j) {
    				for (int k=1;k<=4;++k) {
    					int s=t[j][k];
    					add(f[i][s],f[i-1][j]);
    				}
    			}
    		}
    		for (int i=0;i<(1<<n);++i) add(ans[count(i)],f[m][i]);
    		for (int i=0;i<=n;++i) printf("%d
    ",ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    问题:为命名空间,在此被用作类型和此项目作为引用添加将导致循环依赖项
    关于ObjectDataProvider绑定方法使用案例
    关于C#的数据绑定,存取数据库实例详解 (三)
    关于C#的数据绑定,存取数据库实例详解 (二)
    关于C#的数据绑定,存取数据库实例详解 (一)
    UOS安装到虚拟机上
    连接第三方接口
    工作流
    关于国产项目开发(数据库+服务器+架构)
    字段显示替换
  • 原文地址:https://www.cnblogs.com/owenyu/p/6724616.html
Copyright © 2011-2022 走看看