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