Number String(DP)

题目:

题意:

  给你一个字符串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[i][j]表示:长度为 i ,以数字 j 结尾的数字串的排列有多少种,dp[0][1]=1是确定了的。

    但是在状态转移的时候,我们不得不考虑前面选了什么,也就是状态的设定是有后效性的,
    所以考虑给状态再添一层含义:必须选前i个元素。
    那么这样岂不是每次只能选i吗?那么第二维岂不是没有用了?
    所以我们考虑用j把i替换出来,那么在状态转移的时候就需要考虑放入i时,怎么替换能使原来的大小顺序保持不变。
    将dp[i-1][j]的i-1个数的序列中 ≥j 的数都加1,这样i-1变成了i,j变成了j+1,而j自然就补在后面了。
    处理I:dp[i][j] = Σdp[i-1][x],其中1≤x≤j-1,可进一步简化,dp[i][j] = dp[i][j-1]+dp[i-1][j-1]
    处理D:dp[i][j] = Σdp[i-1][x],其中j≤x≤i-1,可进一步简化,dp[i][j] = dp[i-1][j+1]+dp[i-1][j]
    处理?:dp[i][j] = Σdp[i-1][x],其中1≤x≤i-1 

代码:
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 using namespace std;
 6 typedef long long LL;
 7 const LL mod=1e9+7;
 8 const int N=1005;
 9 char s[N];
10 LL dp[N][N];
11 
12 int main()
13 {
14     while(scanf("%s",s+1)!=EOF)
15     {
16         int len=strlen(s+1);
17         memset(dp,0,sizeof(dp));
18         dp[0][1]=1;
19         for(int i=1;i<=len;i++)
20         {
21             if(s[i]=='I')
22                 for(int j=2;j<=i+1;j++)
23                     dp[i][j]=(dp[i][j-1]+dp[i-1][j-1])%mod;
24             else if(s[i]=='D')
25                 for(int j=i;j>=1;j--)
26                     dp[i][j]=(dp[i][j+1]+dp[i-1][j])%mod;
27             else
28             {
29                 for(int j=1;j<=i+1;j++)
30                     dp[i][j]=(dp[i][j-1]+dp[i-1][j-1])%mod;
31                 LL sum=0;
32                 for(int j=i;j>=1;j--)
33                 {
34                     sum=(sum+dp[i-1][j])%mod;
35                     dp[i][j]=(dp[i][j]+sum)%mod;
36                 }
37             }
38         }
39         LL ans=0;
40         for(int i=1;i<=len+1;i++) ans=(ans+dp[len][i])%mod;
41         printf("%lld\n",ans);
42     }
43     return 0;
44 }
View Code

 

 
posted @ 2019-02-13 18:10  里昂静  阅读(301)  评论(0编辑  收藏  举报