HDU 4055 Number String

Number String

Time Limit: 5000ms
Memory Limit: 32768KB
This problem will be judged on HDU. Original ID: 4055
64-bit integer IO format: %I64d      Java class name: Main
 
The signature of a permutation is a string that is computed as follows: for each pair of consecutive elements of the permutation, write down the letter 'I' (increasing) if the second element is greater than the first one, otherwise write down the letter 'D' (decreasing). For example, the signature of the permutation {3,1,2,7,4,6,5} is "DIIDID".

Your task is as follows: You are given a string describing the signature of many possible permutations, find out how many permutations satisfy this signature.

Note: For any positive integer n, a permutation of n elements is a sequence of length n that contains each of the integers 1 through n exactly once.
 

Input

Each test case consists of a string of 1 to 1000 characters long, containing only the letters 'I', 'D' or '?', representing a permutation signature.

Each test case occupies exactly one single line, without leading or trailing spaces.

Proceed to the end of file. The '?' in these strings can be either 'I' or 'D'.
 

Output

For each test case, print the number of permutations satisfying the signature on a single line. In case the result is too large, print the remainder modulo 1000000007.
 

Sample Input

II
ID
DI
DD
?D
??

Sample Output

1
2
2
1
3
6
Hint
Permutation {1,2,3} has signature "II". Permutations {1,3,2} and {2,3,1} have signature "ID". Permutations {3,1,2} and {2,1,3} have signature "DI". Permutation {3,2,1} has signature "DD". "?D" can be either "ID" or "DD". "??" gives all possible permutations of length 3.

Source

 
解题:动态规划 Regional的题目质量真的很高
 

题目分析:对于一个n个数排列,用I 表示后一个数比前一个数大, 用D表示后一个数比前一个数小。例如:123 就是II 。312就是DI。?表示可以I 或者D。给I,D,?组成的程度为n的序列,找出这个序列所能表示的全排列的个数,每个数字只能出现一次。

显然如果序列的长度为n , 则为1 ~ n+1的排列。

设dp[ i ][ j ] 为 前i - 1 已经排列好 , 第i 位为j的排列数。sigma dp[ n + 1 ][ j ] , j 从1 到n+1 ,为要求的结果。

如果第i位对应 ‘ I ’ ,则dp[ i ][ j ] = dp[ i - 1][ j - 1] + dp[ i - 1][ j - 2] + …… + dp[ i - 1 ][ 1 ] ;

考虑第i位时,前面i - 1 位都已经排好,且第i - 1位的数字 小于 j 的排列都可以在第i位放j , 所以可得上式。

如果第j位对应‘D’ , 则dp[ i ][ j ] = dp[ i - 1][ i - 1] + dp[ i - 1][ i - 2 ] + …… + dp[ i - 1 ][ j ] ;

对于第 i - 1 位的数字大于等于 j  的排列 , 将前 i - 1 位中大于等于j的数字都加1 ,前面的情况依然成立 , 且第 i 位可以放 j 。

例如 (1 ,3 , 2) 。第4位对应D , 想放2 。将前三位大于等于2的加1,得到  (1 , 4, 3 )。将2放在后面,得到(1,4,3,2)。  所以第i - 1 位大于等于 j 的都可以入选 , 因为加1之后 , 肯定比 j 大。

如果第i为对应‘?’ , 则以上两种情况相加。

用sum[ i ][ j ] 表示 dp[ i ][ j ] + dp[ i ][  j - 1 ] + …… + dp[ i ][ 1 ] 

则,状态转移可写成:

对应  I 时 , dp[ i ][ j ] = sum[ i - 1][ j - 1]  

对应 D时 ,dp[ i ][ j ] = sum[ i - 1][ i - 1] - sum[ i - 1][ j - 1]

对应 ?时 , dp[ i ][ j ] = sum[ i - 1 ][ i - 1]

 

以上内容摘自玻璃年华Alex

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int mod = 1000000007;
 5 const int maxn = 1010;
 6 LL dp[maxn][maxn],sum[maxn][maxn];
 7 char str[maxn];
 8 int main(){
 9     while(~scanf("%s",str)){
10         int n = strlen(str)+1;
11         dp[1][1] = sum[1][1] = 1;
12         for(int i = 2; i <= n; ++i){
13             for(int j = 1; j <= i; ++j){
14                 if(str[i - 2] == 'I') dp[i][j] = sum[i - 1][j - 1];
15                 else if(str[i - 2] == 'D') dp[i][j] = (sum[i-1][i-1] - sum[i-1][j-1] + mod)%mod;
16                 else dp[i][j] = sum[i-1][i-1];
17                 sum[i][j] = (sum[i][j-1] + dp[i][j])%mod;
18             }
19         }
20         printf("%I64d\n",sum[n][n]);
21     }
22     return 0;
23 }
View Code

 

posted @ 2015-09-07 15:58  狂徒归来  阅读(166)  评论(0编辑  收藏  举报