符合DI序列的排列数
int numPermsDISequence(string S) {
// 设dp[i][j]表示[0..i]的排列、结尾是j时的DI排列数
// dp[i][j]与子问题dp[i-1][]有什么关系?
// 考虑某排列(如201),它跟比它长1的、分别以0,1,2,3结尾的排列(3120,3021,3012,2013)可以建立一一映射,比如:
// 1) 在201后添上>结尾1的数,比如添上2(=>2012),然后把原排列中>=新添数的都加上1(=>3012),
// 这就构成结尾的*I排列*;过程反过来,3012去掉结尾2(=>301),然后把剩下排列中>=去掉数的都减去1(=>201)。
// 若dp[i][j]的结尾是I排列(如3012=>201),dp[i][j]=sum(dp[i-1][<j])
// 2) 在201后添上<=结尾1的数,比如添上1(=>2011),然后把原排列中>=新添数的都加上1(=>3021),
// 这就构成结尾的*D排列*;过程反过来,3021去掉结尾1(=>302),然后把剩下排列中>=去掉数的都减去1(=>201)。
// 若dp[i][j]的结尾是D排列(如3021=>201),dp[i][j]=sum(dp[i-1][>=j])
// 初始dp[0][0]=1。在i维上只依赖i-1项,可省掉i这维,i仍从左往右遍历。
// 第j维由dp[i-1][<j]、dp[i-1][>=j]决定的遍历顺序冲突,要用临时变量ndp[j]。
const int MOD = 1e9 + 7;
const int N = S.size(); // [0..N]的排列
vector<int> dp(N + 1, 0);
dp[0] = 1; // i==0
for (int i = 1; i <= N; i++) {
vector<int> ndp(N + 1, 0);
for (int j = 0; j <= i; j++) {
if (S[i-1] == 'I') {
for (int k = 0; k < j; k++) {
ndp[j] = (ndp[j] + dp[k]) % MOD;
}
} else {
for (int k = j; k < i; k++) {
ndp[j] = (ndp[j] + dp[k]) % MOD;
}
}
}
swap(dp, ndp);
}
int ans = 0;
for (int j = 0; j <= N; j++) {
ans = (ans + dp[j]) % MOD;
}
return ans;
}
联系:符合DI序列的排列 - 贪心法