Number String(hdu 4055)

题意:给定一个字符串,I表示本字符要比前一个字符大,D表示本字符要不前一个字符小,?可大可小,问1~n的所有排列中,有多少满足条件 

/*
    dp方程的设定比较显然,dp[i][j]表示选了i个元素,最后一个是j的方案数。
    但是在状态转移的时候,我们不得不考虑前面选了什么,也就是状态的设定是有后效性的,
    所以考虑给状态再添一层含义:必须选前i个元素。
    那么这样岂不是每次只能选i吗?那么第二维岂不是没有用了?
    所以我们考虑用j把i替换出来,那么在状态转移的时候就需要考虑放入i时,怎么替换能使原来的大小顺序保持不变。
    将dp[i-1][j]的i-1个数的序列中 ≥j 的数都加1,这样i-1变成了i,j变成了j+1,而j自然就补在后面了。
    处理I:dp[i][j] = Σdp[i-1][x],其中1≤x≤j-1,可进一步简化,dp[i][j] = dp[i][j-1]+dp[i-1][j-1]
    处理D:dp[i][j] = Σdp[i-1][x],其中j≤x≤i-1,可进一步简化,dp[i][j] = dp[i-1][j+1]+dp[i-1][j]
    处理?:dp[i][j] = Σdp[i-1][x],其中1≤x≤i-1 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1010
#define mod 1000000007
using namespace std;
int dp[N][N],n;
char s[N];
int main(){
    while(scanf("%s",s+1)!=EOF){
        memset(dp,0,sizeof(dp));
        n=strlen(s+1);n++;
        dp[1][1]=1;
        for(int i=2;i<=n;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][j+1]+dp[i-1][j])%mod;
            }
            else {
                int sum=0;
                for(int j=1;j<i;j++)
                    sum+=dp[i-1][j],sum%=mod;
                for(int j=1;j<=i;j++)
                    dp[i][j]=sum;
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            ans+=dp[n][i],ans%=mod;
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/harden/p/6730892.html