HDU 4055 Number String:前缀和优化dp【增长趋势——处理重复选数】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4055

题意:

  给你一个由'I', 'D', '?'组成的字符串,长度为n,代表了一个1~n+1的排列中(数字不重复),相邻数字的增长趋势。('I'为增,'D'为减,'?'为未知)

  问你符合条件的数列有多少种。

题解:

  表示状态:

    dp[i][j] = combinations

    表示长度为i的排列(由1~i组成),末尾为j,这样的排列的个数

  找出答案:

    ans = ∑ dp[n][1 to n]

  如何转移:

    先考虑增长('I')。

    对于dp[i][j],是由dp[i-1][k with k < j]在末尾添加一个j得到的。

    也就是:

      dp[i][j] = ∑ dp[i-1][1 to j-1]

    可是在dp[i-1][k with k < j]的数列中,由可能j已经选过。

    为了处理这种情况,可以想成将原来数列中 >= j的数都+1。

    这样并不影响原数列的增长性,也不影响答案。

    对于'D'和'?'同理:

      D: dp[i][j] = ∑ dp[i-1][j to i-1]

      ?: dp[i][j] = ∑ dp[i-1][1 to i-1]

AC Code:

 1 // state expression:
 2 // dp[i][j] = combinations
 3 // i: considering ith num
 4 // j: last num
 5 //
 6 // find the answer:
 7 // sigma dp[n][1 to n]
 8 //
 9 // transferring:
10 // if increase
11 // dp[i][j] = sigma dp[i-1][1 to j-1]
12 // if decrease
13 // dp[i][j] = sigma dp[i-1][j+1 to i-1]
14 //
15 // boundary:
16 // dp[1][1] = 1
17 // others = 0
18 #include <iostream>
19 #include <stdio.h>
20 #include <string.h>
21 #define MAX_N 1005
22 #define MOD 1000000007
23 
24 using namespace std;
25 
26 int n;
27 int ans;
28 int dp[MAX_N][MAX_N];
29 int sum[MAX_N][MAX_N];
30 string s;
31 
32 int cal_mod(int a)
33 {
34     return (a%MOD+MOD)%MOD;
35 }
36 
37 int cal_sum(int i,int x,int y)
38 {
39     if(x>y) return 0;
40     if(x==0) return sum[i][y];
41     return cal_mod(sum[i][y]-sum[i][x-1]);
42 }
43 
44 void update_sum(int i,int j,int a)
45 {
46     if(j==0) sum[i][j]=cal_mod(a);
47     else sum[i][j]=cal_mod(sum[i][j-1]+a);
48 }
49 
50 void solve()
51 {
52     n=s.size()+1;
53     memset(dp,0,sizeof(dp));
54     memset(sum,0,sizeof(sum));
55     dp[1][1]=1;
56     for(int i=1;i<=n;i++) sum[1][i]=1;
57     for(int i=2;i<=n;i++)
58     {
59         for(int j=1;j<=i;j++)
60         {
61             if(s[i-2]=='I') dp[i][j]=cal_sum(i-1,1,j-1);
62             else if(s[i-2]=='D') dp[i][j]=cal_sum(i-1,j,i-1);
63             else dp[i][j]=cal_sum(i-1,1,i-1);
64             update_sum(i,j,dp[i][j]);
65         }
66     }
67     ans=cal_sum(n,1,n);
68 }
69 
70 void print()
71 {
72     cout<<ans<<endl;
73 }
74 
75 int main()
76 {
77     while(cin>>s)
78     {
79         solve();
80         print();
81     }
82 }
原文地址:https://www.cnblogs.com/Leohh/p/7767044.html