• HDU 4899 Hero meet devil (状压DP, DP预处理)


    题意:给你一个基因序列s(只有A,T,C,G四个字符,假设长度为n),问长度为m的基因序列s1中与给定的基因序列LCS是0,1......n的有多少个?

    思路:最直接的方法是暴力枚举长度为m的串,然后再用求LCS的dp。当然我们可以在枚举的时候同时进行dp,但是复杂的仍然为O(4 ^ m)。我们可以观察求LCS 的状态转移方程:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) 若s[i] == s1[j] dp[i][j] = max(dp[i - 1][j - 1] + 1)。可以发现,每一行的相邻的状态最多只会差1,那么我们可以用差分的方法转化为状压dp。剩下的部分这两篇博客讲的很清楚了:https://www.cnblogs.com/RabbitHu/p/BZOJ3864.html, https://www.cnblogs.com/owenyu/p/6724616.html

    代码:

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const LL mod = 1000000007;
    const int maxn = 1010;
    char mp[4] = {'A', 'T', 'C', 'G'};
    int ans[20];
    int dp[2][1 << 15];
    int trans[1 << 15][4], cnt[1 << 15];
    char s[maxn];
    void init(int n) {
    	int pre[20], cur[20];
    	memset(pre, 0, sizeof(pre));
    	memset(cur, 0, sizeof(cur));
    	for (int i = 0; i < (1 << n); i++) {
    		if(i)cnt[i] = cnt[i >> 1] + (i & 1);
    		pre[0] = i & 1;
    		for (int j = 1; j < n; j++)
    			pre[j] = pre[j - 1] + (i >> j & 1); 
    		for (int k = 0; k < 4; k++) {
    			int now = 0;
    			cur[0] = pre[0];
    			if(mp[k] == s[0]) cur[0] = 1;
    			now |= cur[0];
    			for (int j = 1; j < n; j++) {
    				cur[j] = max(cur[j - 1], pre[j]);
    				if(mp[k] == s[j]) {
    					cur[j] = max(cur[j], pre[j - 1] + 1);
    				}
    				now |= ((cur[j] - cur[j - 1]) << j);
    			}
    			trans[i][k] = now;
    		}
    	}
    }
    int main() {
    	int T, m, n;
    	scanf("%d", &T);
    	while(T--) {
    		scanf("%s", s);
    		scanf("%d", &m);
    		int n = strlen(s);
    		init(n);
    		memset(dp, 0, sizeof(dp));
    		memset(ans, 0, sizeof(ans));
    		dp[0][0] = 1;	
    		for (int i = 1; i <= m; i++) {
    			memset(dp[i & 1], 0, sizeof(dp[i & 1]));
    			int pre = (i & 1) ^ 1;
    			int now = i & 1;
    			for (int j = 0; j < (1 << n); j++) {
    				for (int k = 0; k < 4; k++) {
    					dp[now][trans[j][k]] = (dp[pre][j] + dp[now][trans[j][k]]) % mod;
    				}
    			}
    		}	
    		for (int i = 0; i < (1 << n); i++)
    			ans[cnt[i]] = (ans[cnt[i]] + dp[m & 1][i]) % mod;
    		for(int i = 0; i <= n; i++)
    			printf("%d
    ", ans[i]); 
    	}
    }
    

      

  • 相关阅读:
    Word Puzzles [POJ 1204]
    set用法
    FOJ有奖月赛2012年11月
    BerDonalds
    POJ1469 匈牙利算法
    后缀数组
    ZOJ Monthly, January 2013
    算法导论<一>
    Yell Classico
    点聚 WebOffice 编辑辅助控件 WebOffice.OCX
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10440763.html
Copyright © 2020-2023  润新知