hdu4055

hdu4055

题意

给出一个长度为 n - 1 的字符串,要求构造一个包含数字 [1, n] 的排列,从第二位开始,'I' 表示当前位数字比前一位大,'D' 表示当前位数字比前一位小,'?' 表示可大可小。问有多少满足条件的 n 的排列。

分析

设 dp[i][j] 为 [1, i] 已排列好,最后一位为 j 的方案数。
如果 s[i] = 'I', \(dp[i][j] = \sum_{k=1}^{j-1}{dp[i-1][k]}\);
如果 s[i] = 'D', \(dp[i][j] = \sum_{k=j}^{i-1}{dp[i-1][k]}\);
我们可以假定每次使第 i 位为 j 时,前面 >= j 的值都加 1 了,保证仍是一个完整的排列。
注意到我们主要用到的是 dp[i-1][k] 的累加和,可以让 sum[i - 1][k] 表示 \(\sum_{x=1}^{k}dp[i-1][x]\) 的和。
前缀和快速求解。sum数组可以改用滚动数组实现。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 5005;
const int MOD = 1e9 + 7;
int dp[MAXN][MAXN];
int sum[MAXN][MAXN];
char s[MAXN];
int main() {
    while(~scanf("%s", s)) {
        int l = strlen(s);
        sum[1][1] = 1;
        for(int i = 2; i < l + 2; i++) {
            for(int j = 1; j <= i; j++) {
                if(s[i - 2] == 'I') {
                    dp[i][j] = sum[i - 1][j - 1];
                } else if(s[i - 2] == 'D') {
                    dp[i][j] = (sum[i - 1][i - 1] - sum[i - 1][j - 1] + MOD) % MOD;
                } else {
                    dp[i][j] = sum[i - 1][i - 1];
                }
                sum[i][j] = (sum[i][j - 1] + dp[i][j]) % MOD;
            }
        }
        printf("%d\n", sum[l + 1][l + 1]);
    }
    return 0;
}
posted @ 2017-06-21 01:38  ftae  阅读(170)  评论(0编辑  收藏  举报