DP套DP HDOJ 4899 Hero meet devil(國王的子民的DNA)

 

題目連接c++

題意:3d

  給n長度的S串,對於0<=i<=|S|,有多少個長度爲m的T串,使得LCS(S,T) = i。blog

思路:it

  理解的不是很透徹,先佔個坑。class

#include <bits/stdc++.h>

const int S = (1 << 15) + 5;
const int MOD = 1e9 + 7;

char color[] = "ATGC";
char s[20];
int pre[20], lcs[20];
int dp[2][S], add[S][4];
int ans[20];
int n, m;

void add_mod(int &a, int b) {
    a += b;
    if (a >= MOD) {
        a -= MOD;
    }
}

int bit_count(int x) {
    return x ? bit_count (x >> 1) + (x & 1) : x;
}

void init() {
    n = strlen (s + 1);
    for (int state=0; state<(1<<n); ++state) {  //狀壓枚舉S與T公共點的組合
        pre[0] = 0;
        for (int i=1; i<=n; ++i) {
            pre[i] = pre[i-1] + ((state>>(i-1)) & 1);  //S匹配到前i個時LCS的長度
        }
        for (int k=0; k<4; ++k) {  //T的某一個位置是color[k],新的LCS的長度和公共點位置
            for (int i=1; i<=n; ++i) {
                if (s[i] == color[k]) {
                    lcs[i] = pre[i-1] + 1;
                } else {
                    lcs[i] = std::max (lcs[i-1], pre[i]);
                }
            }

            int &tmp = add[state][k] = 0;  //對於state狀態,加一個顏色k後新的state
            for (int i=1; i<=n; ++i) {
                tmp |= ((lcs[i]!=lcs[i-1]) << (i-1));
            }
        }
    }
}

void solve() {
    int now = 0;
    memset (dp[now], 0, sizeof (dp[now]));
    dp[now][0] = 1;
    for (int i=1; i<=m; ++i) {
        now ^= 1;
        memset (dp[now], 0, sizeof (dp[now]));
        for (int state=0; state<(1<<n); ++state) {
            for (int k=0; k<4; ++k) {
                add_mod (dp[now][add[state][k]], dp[now^1][state]);
            }
        }
    }
    memset (ans, 0, sizeof (ans));
    for (int state=0; state<(1<<n); ++state) {
        add_mod (ans[bit_count (state)], dp[now][state]);
    }
    for (int i=0; i<=n; ++i) {
        printf ("%d\n", ans[i]);
    }
}

int main() {
    int T;
    scanf ("%d", &T);
    while (T--) {
        scanf ("%s", s + 1);
        scanf ("%d", &m);
        init ();
        
        solve ();
    }
    return 0;
}
相關文章
相關標籤/搜索