HDU 4055 Number String(不錯的DP題)
阿新 • • 發佈:2019-02-06
題意:
給你一個字串s,s[i] = 'D'表示排列中a[i] > a[i+1],s[i] = 'I'表示排列中a[i] < a[i+1]。
比如排列 {3, 1, 2, 7, 4, 6, 5} 表示為字串 DIIDID。
解題思路:
很巧妙的DP做法,dp[i][j]表示前i個滿足字串條件的結尾為j的 i 的排列,注意是i的排列,前面並沒有數大於i。那又是如何往下遞推呢?
如果s[i - 1]是' I ',那麼dp[i][j] = dp[i-1][j-1] + dp[i-1][j-2] + .. + dp[i-1][1]
如果s[i - 1]是‘D’,那麼dp[i][j] = dp[i-1][j] + dp[i-1][j+1] + ... + dp[i-1][i],因為要令當前位為j,如果前面出現過j,就令前面的所有大於等於j的數+1,就能構造出新的排列了。比如
{1, 3, 5, 2, 4},要在第六位插入3,令 >= 3的數都+1,於是就構造出新的 排列{1, 4, 6, 2, 5, 3}。然後程式碼的話處理出字首和sum[i][j],就不用dp[i][j]了。感覺還是很巧妙的,好題!
/* ********************************************** Author : JayYe Created Time: 2013/10/6 23:22:51 File Name : Orz.cpp *********************************************** */ #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; typedef __int64 ll; const int maxn = 1000 + 5; const int mod = 1000000007; ll sum[maxn][maxn]; char s[maxn]; int main() { while(scanf("%s", s) != -1) { int len = strlen(s); sum[0][1] = 1; for(int i = 1;i <= len; i++) { for(int j = 1;j <= i+1; j++) { sum[i][j] = sum[i][j-1]; if(s[i-1] != 'D') sum[i][j] += sum[i-1][j-1]; if(s[i-1] != 'I') sum[i][j] += sum[i-1][i] - sum[i-1][j-1] + mod; sum[i][j] %= mod; } } printf("%I64d\n", sum[len][len+1]); } return 0; }