首页 > 代码库 > ZOJ 3543 Number String 【2011大连区域赛】【dp】

ZOJ 3543 Number String 【2011大连区域赛】【dp】

题意

给出一串由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;
}


ZOJ 3543 Number String 【2011大连区域赛】【dp】