[DP]HDU 4055 Number String

與排列相關的dp,但這類dp不太懂。

定義狀態:dp[i][j]表示長度爲i,末尾爲j的序列的個數。

轉移方程:    if(s[i - 1] == 'I' || s[i - 1] == '?') dp[i][j]= sum[i - 1][j - 1];

                     if(s[i- 1] == 'D' || s[i - 1] == '?') dp[i][j] += sum[i - 1][i] - sum[i - 1][j - 1];

其中,sump[i][j]表示長度爲i,末尾小於等於j的所有序列之和。

轉移方程如何解釋呢:

------------------------------------------------------------------------------------------------------------------------------------------

處理完dp[i-1][]後,加入的數即爲i,而dp[i][j]是要將i放進去j換出來,而這裏有一種將i放進去j換出來,同時不影響升降順序的方法是:

將dp[i-1][j]的i-1個數的序列中 ≥j的數都加1,這樣i-1變成了i,j變成了j+1,而j自然就補在後面了。

轉自:一步一步向上爬... 

------------------------------------------------------------------------------------------------------------------------------------------

利用sum來把複雜度爲O(n^3)的將爲O(n^2)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL long long
const int N = 1010;
const int M = 1000000007;
int f[N][N], sum[N][N];
char s[N];

int main()
{
//    freopen("input.txt", "r", stdin);
    for(int i = 1; i < N; i++) sum[0][i] = 1;
    while(scanf("%s", s) == 1){
        int n = strlen(s);
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= i + 1; j++){
                f[i][j] = sum[i][j] = 0;
                if(s[i - 1] == 'I' || s[i - 1] == '?'){
                    f[i][j] = sum[i - 1][j - 1];
                }
                if(s[i - 1] == 'D' || s[i - 1] == '?'){
                    f[i][j] = ((LL)f[i][j] + M + sum[i - 1][i] - sum[i - 1][j - 1]) % M;
                }
                sum[i][j] = ((LL)sum[i][j - 1] + f[i][j]) % M;
            }
        }
        printf("%d\n", sum[n][n + 1]);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章