HDU 4055 Number String:字首和優化dp【增長趨勢——處理重複選數】

Leohh發表於2017-11-01

題目連結: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 }

 

相關文章