2011 ACM-ICPC Dalian Regional Contest Problem E (ZOJ 3543) Number String

题目

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3543

题意

有一串序列,'I'表示当前位置的数比后一位的小,'D'表示当前位置的数比后一位的大,'?'表示当前位置可能是'I'也可能是'D',求序列可能的种类数

解法

有结论:{1,...,N}的排列数等于{1,...,j-1, j+1,...,i+1}的排列数

状态定义
dp[i][j]表示长度为i的以j为结尾的合法排列个数
  1. 对于'I', 有\(dp[i][j] += dp[i-1][k], (0 <= k < j)\)
  2. 对于'D', 有\(dp[i][j] += dp[i-1][k], (j <= k < i)\)
  3. 对于'?', 1 和 2 各进行一次

利用部分和 \(sum[i][j] = dp[i][1] + dp[i][2] + ... + dp[i][j]\)

代码

#include <cstdio>
#include <cstring>
const int N = 1010;
const int MOD = 1e9 + 7;
int dp[N][N], sum[N][N];
char s[N];
int main() {
    while(~scanf("%s", s + 2)) {
        int n = strlen(s + 2) + 1;
        memset(dp, 0, sizeof(dp));
        memset(sum, 0, sizeof(sum));
        dp[1][1] = sum[1][1] = 1;
        for(int i = 2; i <= n; i++) {
            for(int j = 1; j <= i; j++) {
                if(s[i] == 'I' || s[i] == '?') {
                    dp[i][j] = (dp[i][j] + sum[i - 1][j - 1]) % MOD;
                }
                if(s[i] == 'D' || s[i] == '?') {
                    dp[i][j] = (dp[i][j] + sum[i - 1][i - 1] - sum[i - 1][j - 1] + MOD) % MOD;
                }
                sum[i][j] = (sum[i][j - 1] + dp[i][j]) % MOD;
            }
        }
        printf("%d\n", sum[n][n]);
    }
    return 0;
}

Source

The 2011 ACM-ICPC Asia Dalian Regional Contest

posted @ 2015-08-12 22:39  ACM_Record  阅读(145)  评论(0编辑  收藏  举报