hdu 4055 Number String

Number String

http://acm.hdu.edu.cn/showproblem.php?pid=4055php

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)優化

Problem Description
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.
 
 
題意:
給出長爲n的一個字符串,根據這個字符串構造長爲n+1的數字串
字符爲‘I’,下一個數字要比這一個數字大
字符爲‘D’ ,下一個數字要比這一個數字小
字符爲‘?’,下一個數字沒有限制
問數字串有多少種方案
 
通常套路:
f[i][j]表示長爲i的串中,最後一個數字爲j的方案數
若字符爲‘I’,f[i][j]= Σ f[i-1][x]   1 <= x < j     
若字符爲‘D’,f[i][j]= Σ f[i-1][x]  j <= x <= i-1  
若字符爲‘?’,f[i][j]=Σ f[i-1][x]  1 <= x <= i-1
咱們雖然根據 字符保證了相鄰兩個數字的大小關係,但並無保證數字串裏前i-1個數字沒有數字j
這就有了後效性。怎麼辦?
給狀態增長含義:必須選前i-1個數字
咱們將過程想象爲一個一個填數字的過程
那麼由f[i-1][]向f[i][]的轉移,就是在末尾(i位置)填上數字i
(由於狀態的定義是必須選前i-1個數字)
那麼豈不是隻能填數字i?字符爲‘D’時不就錯了嗎?第二維不就沒有用嗎?
咱們考慮第二維j(要填的最後一個數字),
咱們是否能夠將填數字i轉換到填數字j,
那麼狀態轉移的時候,就要想如何填j使相鄰數字的大小關係不變
將前i-1個數字>=j的都+1,這樣就拿出了j,放在最後面
因此,上方狀態轉移成立
時間複雜度?O(n³) TLE
 
前綴和優化,時間複雜度O(n²)
其實很簡單,照着原方程x的取值範圍寫就行
 1 <= x < j     前綴和就是sum[i-1][j-1]
j <= x <= i-1  前綴和就是 sum[i-1][i-1]-sum[i-1][j-1]
 1 <= x <= i-1  前綴和就是sum[i-1][i-1]
前綴和的更新: sum[i][j]=(sum[i][j-1]+f[i][j])%mod;
 
前綴和優化代碼
#include<cstdio>
#include<cstring>
#define mod 1000000007
using namespace std;
int len,f[1002][1002],sum[1002][1002];
char s[1001];
int main()
{
    while(scanf("%s",s+1)!=EOF)
    {
        memset(f,0,sizeof(f));
        len=strlen(s+1);
        f[1][1]=1; sum[1][1]=1;
        for(int i=2;i<=len+1;i++)
              for(int j=1;j<=i;j++)
             {
                 if(s[i-1]=='I') f[i][j]=sum[i-1][j-1];
                 else if(s[i-1]=='D') f[i][j]=((sum[i-1][i-1]-sum[i-1][j-1])%mod+mod)%mod;
                 else f[i][j]=sum[i-1][i-1];
                 sum[i][j]=(sum[i][j-1]+f[i][j])%mod;
             }
        printf("%d\n",sum[len+1][len+1]); 
    }
}

 

未優化代碼this

#include<cstdio>
#include<cstring>
#define mod 1000000007
using namespace std;
int len,f[1002][1002];
char s[1001];
int main()
{
    while(scanf("%s",s+1)!=EOF)
    {
        memset(f,0,sizeof(f));
        len=strlen(s+1);
        f[1][1]=1;
        for(int i=2;i<=len+1;i++)
         for(int j=1;j<=i;j++)
         {
             if(s[i-1]=='I') 
             for(int k=1;k<j;k++) f[i][j]+=f[i-1][k];
             else if(s[i-1]=='D')
             for(int k=j;k<i;k++) f[i][j]+=f[i-1][k];
             else
             for(int k=1;k<i;k++) f[i][j]+=f[i-1][k];
         }
        int ans=0;
        for(int i=1;i<=len+1;i++) ans+=f[len+1][i];
        printf("%d\n",ans); 
    }
}
相關文章
相關標籤/搜索