HDU--4055(DP*)

2015-06-09 20:35:57

题目:题意比较简单,有 n+1 个数组成若干排列,给出 n 个字符,每个字符为 ‘I' / ’D‘ / ’?',分别表示排列中前一个数到后一个数是 上升/下降/上升或下降 的关系。问在 n+1 个数的所有排列中有多少个排列符合条件。

思路:这题虽然在现场过了很多支队伍(70左右),但是自己模拟的时候硬是想不出来... 太弱了。

  dp 是听明显的,状态定义也很自然,dp[i][j] 表示 i 个数的排列结尾是 j 且满足条件的排列数。

  如果遇到 'I',dp[i][j] = dp[i - 1][1] + dp[i - 1][2] + .... + dp[i][j - 1]

  如果遇到 'D'  dp[i][j] = dp[i - 1][j] + dp[i - 1][j + 1] + ... + dp[i - 1][i - 1]

  如果是 '?' 那么就是前两式的和

  第一条比较好理解,在 i - 1 长度里找结尾比 j 小的即可。考虑第二条,我需要在排列中加入 i 这个数,且使得结尾是 j,我们可以把 i - 1 个数排列

  中 >= j 的数全部 +1,这样就会剩下 j 一个数没有加,放在最后面即可。(这个思路是不断加入数,巧妙利用了 dp 的递推性,第二条转化方法值得思考)

 

  ※具体实现中我把 dp 定义为了前缀和,为了方便。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const ll mod = 1000000007;

char s[1010];
ll dp[1010][1010];

int main(){
    while(scanf("%s",s + 1) != EOF){
        int len = strlen(s + 1);
        for(int i = 1; i <= len + 1; ++i)
            dp[1][i] = 1;
        for(int i = 2; i <= len + 1; ++i){
            if(s[i - 1] == 'I'){
                for(int j = 1; 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 = 1; j <= i; ++j)
                    dp[i][j] = (dp[i][j - 1] +
                            dp[i - 1][i - 1] - dp[i - 1][j - 1] + mod) % mod;
            }
            else{
                for(int j = 1; j <= i; ++j)
                    dp[i][j] = (dp[i][j - 1] + dp[i - 1][i - 1]) % mod;
            }
        }
        printf("%I64d\n",dp[len + 1][len + 1]);
    }
    return 0;
}

 

posted @ 2015-06-09 20:51  Naturain  阅读(129)  评论(0编辑  收藏  举报