Cho chuỗi S gồm 'D' (giảm) và 'I' (tăng). Hoán vị P của {0..n} hợp lệ nếu: S[i]=='D' ⇒ P[i] > P[i+1]; S[i]=='I' ⇒ P[i] < P[i+1]. Đếm số hoán vị hợp lệ modulo 10^9+7.
Ví dụ: "IDD" → 3.
Giải thuật
- DP: dp[i][j] = số cách xếp i+1 số đầu tiên (0..i) sao cho thỏa mãn i ký tự đầu của S, và số cuối cùng là j-th nhỏ nhất trong các số còn lại.
- Khởi tạo dp[0][j] = 1 (với 1 số, luôn hợp lệ).
- Duyệt i từ 0 đến n-1:
- Nếu S[i]=='I': duyệt j từ 0 đến n-i-1, cộng dồn curr = (dp[i][j] + curr) % mod, dp[i+1][j] += curr.
- Nếu S[i]=='D': duyệt j từ n-i-1 xuống 0, cộng dồn curr = (dp[i][j+1] + curr) % mod, dp[i+1][j] += curr.
- Kết quả dp[n][0].
Ví dụ mã C++
#include <bits/stdc++.h>
using namespace std;
const int m = 1e9 + 7;
class Solution {
public:
int numPermsDISequence(string S) {
int n = S.size();
vector<vector<int>> dp(n + 1, vector<int>(n + 1));
for (int j = 0; j <= n; j++) dp[0][j] = 1;
for (int i = 0; i < n; i++) {
if (S[i] == 'I') {
for (int j = 0, curr = 0; j < n - i; j++) {
curr = (dp[i][j] + curr) % m;
dp[i + 1][j] = (dp[i + 1][j] + curr) % m;
}
} else {
for (int j = n - i - 1, curr = 0; j >= 0; j--) {
curr = (dp[i][j + 1] + curr) % m;
dp[i + 1][j] = (dp[i + 1][j] + curr) % m;
}
}
}
return dp[n][0];
}
};
int main(){
Solution ob;
cout << (ob.numPermsDISequence("IDD"));
}
Đầu vào
"IDD"
Đầu ra
3