bzoj 3864: Hero meet devil [dp套dp]


3864: Hero meet devil

題意:

給你一個只由AGCT組成的字符串S (|S| ≤ 15),對於每個0 ≤ .. ≤ |S|,問
有多少個只由AGCT組成的長度為m(1 ≤ m ≤ 1000)的字符串T,使得\(LCS(T,S) = i\)


dp套dp!

通過一個外層的dp來計算使得另一個dp方程(子dp)最終結果為特定值輸入數

一位一位確定子dp的輸入,記錄子dp的狀態值


子dp:

\(d(i,j)\)表示\(LCS(T[1,i],S[1,j])\),對第二維差分,\(j\)\(j-1\)只可能相差0/1,可以狀壓

外層dp:

\(f(i,s)\)表示確定到T的第i位,子dp狀態值為s的方案數

預處理子dp每種狀態值加一個字符后的轉移,然后進行外層dp即可


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 1005, mo = 1e9+7;
inline int read() {
    char c=getchar(); int x=0,f=1;
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*f;
}

int n, m; char str[20], c[10] = "ACGT";
int trans[1<<15][4], one[1<<15], f[2][1<<15];
void init() {
	static int d[20], g[20];
	for(int s=0; s < 1<<n; s++) {
		if(s) one[s] = one[s ^ (s&-s)] + 1;
		for(int j=0; j<n; j++) d[j+1] = d[j] + bool(s & (1<<j));
		for(int k=0; k<4; k++) {
			for(int j=1; j<=n; j++) {
				g[j] = max(g[j-1], d[j]);
				if(c[k] == str[j]) g[j] = max(g[j], d[j-1]+1);
			}
			trans[s][k] = 0;
			for(int j=0; j<n; j++) if(g[j+1] - g[j]) trans[s][k] |= 1<<j; 
		}
	}
}
int ans[N];
int main() {
	freopen("in", "r", stdin);
	int T = read();
	while(T--) {
		scanf("%s", str+1); m = read(); n = strlen(str+1);
		init();
		memset(ans, 0, sizeof(ans));
		memset(f, 0, sizeof(f));
		f[0][0] = 1; int p = 0;
		for(int i=1; i<=m; i++, p ^= 1) {
			memset(f[p^1], 0, sizeof(f[p^1]));
			for(int s=0; s < 1<<n; s++)
				for(int k=0; k<4; k++) (f[p^1][trans[s][k]] += f[p][s]) %= mo;
		}
		for(int s=0; s < 1<<n; s++) (ans[one[s]] += f[p][s]) %= mo;
		for(int i=0; i<=n; i++) printf("%d\n", ans[i]);
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM