计数dp + 排列组合
题意:
有一列数字,当第i数字比前一个数字大的时候就可以生成一个字符I,否则就是D,现在给出字符串,求出数列有多少种排列方式,注意字符串?代表比前一个数字大小都可以。
思路:
此类题可以从当前第i数字是哪一个考虑。
定义:dp[i][j] 表示第i个数字是j的组合数。
那么当第i个字符串是‘I’,dp[i][j]=sum(dp[i−1][1]+...+dp[i−1][j−1])=dp[i][j−1]+dp[i−1][j−1]
是”D”的时候:
dp[i][j]=sum(dp[i−1][j]+dp[i−1][j+1]+...+dp[i−1][i])=dp[i−1][j]+dp[i][j+1]
这里需要注意的点是可以优化,为什么,因为在计算的时候,是递推性质的,可以利用到前一个结果,具体看代码。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e3+10;
const int mod = 1000000007;
typedef long long LL;
char s[maxn];
LL dp[maxn][maxn];
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%s",s+1) != EOF) {
int len = strlen(s+1)+1;
memset(dp,0,sizeof(dp));
dp[1][1] = 1;
for(int i = 2;i <= len; i++) {
if(s[i-1] == 'I') {
for(int j = 2;j <= i; j++) {
dp[i][j] = (dp[i][j-1] + dp[i-1][j-1])%mod;
}
}
else if(s[i-1] == 'D') {
for(int j = i-1;j >= 1; j--) {
dp[i][j] = (dp[i-1][j] + dp[i][j+1])%mod;
}
}
else {
LL sum = 0;
for(int j = 1;j < i; j++) {
sum = (sum + dp[i-1][j])%mod;
}
for(int j = 1;j <= i; j++) {
dp[i][j] = sum;
}
}
}
LL ans = 0;
for(int i = 1;i <= len; i++) {
ans = (ans + dp[len][i])%mod;
}
printf("%I64d\n",ans);
}
return 0;
}