與排列相關的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;
}