• HDU 4055:Number String(DP计数)


    http://acm.hdu.edu.cn/showproblem.php?pid=4055

    题意:给一个仅包含‘I','D','?'的字符串,’I'表示前面的数字比后面的数字要小(Increase升序),'D'表示前面的数字比前面的数字要大(Decrease降序),'?'表示有可能是'I'也有可能是'D',长度为n的字符串就有n+1个数字,在这n+1个数字里面,问符合给出的字符串的条件的序列数有多少种。

    思路:dp[i][j]的定义:i表示当前枚举到第i个字符(即长度为i+1的时候的序列),j表示当前序列长度为i+1的时候第i+1位插入的数是什么,dp[i][j]表示长度为i+1的序列末尾为j的序列数总共有多少种。

    首先需要转化一个思维:即例如前面序列长度为3,假设s[4] = 'D', 那么加入当前的数的时候,即(3, 1, 2),现在枚举的是dp[4][1],即要插入1,那么可以当成前面大于等于1(j)的数全部+1,序列就变成(4, 2, 3, 1),因此可以用前面的来推出后面的。

    当s[i]为'I'的时候,插入的数要比前面一位大,因此前面一位是(1~j-1)的时候都可以插入,所以dp[i][j] = dp[i-1][j-1] + ... + dp[i-1][1].

    当s[i]为'D'的时候,插入的数要比前面一位小,前面说了,要插入的数j在前面重复的时候,可以把前面的大于等于j的数都+1,所以前面是(j~i)都可以插入(j也是可取的,因为+1就变成j+1了),dp[i][j] = dp[i-1][j] + ... + dp[i-1][i].

    这个式子是可以处理出前缀和的,即每次都把dp[i][j] = dp[i][j-1]这样就可以累加起来了。

    而且当前的i只和i-1有关,可以使用滚动数组,还有交C++如果MOD运算过多会超时。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 #define N 1010
     5 const int MOD = 1e9 + 7;
     6 LL dp[2][N];
     7 char s[N];
     8 int main() {
     9     while(~scanf("%s", s + 1)) {
    10         int n = strlen(s + 1);
    11         memset(dp, 0, sizeof(dp));
    12         int pre = 0, now = 1;
    13         dp[pre][1] = 1;
    14         for(int i = 1; i <= n; i++) {
    15             for(int j = 1; j <= i + 1; j++) {
    16                 dp[now][j] = dp[now][j-1]; // 前缀和
    17                 if(s[i] != 'I') dp[now][j] = (dp[now][j] + (dp[pre][i] - dp[pre][j-1]) + MOD) % MOD;
    18                 if(s[i] != 'D') dp[now][j] = (dp[now][j] + dp[pre][j-1]) % MOD;
    19             }
    20             pre ^= now; now ^= pre; pre ^= now;
    21         }
    22         printf("%lld
    ", dp[n%2][n+1]);
    23     }
    24     return 0;
    25 }
  • 相关阅读:
    UML序列图
    接口初探
    Discuz初探
    Vim指令学习
    UCenter Home代码研读之space.php
    建站须知
    linux指令之文件的创建、查询、修改
    InitPHP初探
    php环境搭建
    Zend Framework学习之Zend_Db 数据库操作
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6830273.html
Copyright © 2020-2023  润新知