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为结尾的合法排列个数
- 对于'I', 有\(dp[i][j] += dp[i-1][k], (0 <= k < j)\)
- 对于'D', 有\(dp[i][j] += dp[i-1][k], (j <= k < i)\)
- 对于'?', 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