题意
给出一串由D,I,?构成的长为n的字符串,这个字符串表示满足某种规则的1到n+1的排列集合,D表示该位置数字比前面一个小,I表示该位置的数字比前面一个大,?表示不确定可D可I
比如
满足DI的数字排列有3,1,2和2,1,3
1<=n<=1000,求有多少种满足此条件的字符串
设计的dp如下
dp[i][j] 代表满足上述字符串前i-1项的长为i尾巴为j的1到i的排列数目
当第i-1项为D时
dp[i][j]=sigma(dp[i-1][k]),i-1=>k>=j
当第i-1项为I时
dp[i][j]=sigma(dp[i-1][k]),j>k>=1
最后输出sigma(dp[n+1][k]),1<=k<=n+1
为什么是这样,原因是1到i-1的排列的后面一位写上j的时候,把前面i-1个数大于等于j的数都加1,便得到一个新的1到i的排列
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
using namespace std;
#define LL long long
const LL MOD=1000000007;
char str[2222];
LL dp[1111][1111];
LL sum[1111][1111];
int main(){
#ifndef ONLINE_JUDGE
freopen("H:/in.txt","r",stdin);
#endif // ONLINE_JUDGE
while(scanf("%s",str+2)!=EOF){
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
dp[1][1]=1;
sum[1][1]=1;
LL len=strlen(str+2);
for(LL i=2;i<2+len;i++){
for(LL j=1;j<=i;j++){
if(str[i]=='D' || str[i]=='?'){
dp[i][j]+=sum[i-1][i-1]-sum[i-1][j-1];
dp[i][j]=(dp[i][j]+MOD)%MOD;
}
if(str[i]=='I' || str[i]=='?'){
dp[i][j]+=sum[i-1][j-1];
dp[i][j]=(dp[i][j]+MOD)%MOD;
}
sum[i][j]=(sum[i][j-1]+dp[i][j])%MOD;
}
}
LL ans=0;
for(LL i=1;i<=len+1;i++) ans=(ans+dp[len+1][i])%MOD;
printf("%lld\n",ans);
}
return 0;
}