给出一个长度为 n - 1 的字符串,要求构造一个包含数字 [1, n] 的排列,从第二位开始,'I' 表示当前位数字比前一位大,'D' 表示当前位数字比前一位小,'?' 表示可大可小。问有多少知足条件的 n 的排列。php
设 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数组能够改用滚动数组实现。数组
#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; }