zoukankan      html  css  js  c++  java
  • hdu 4055 Number String

    Number String

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

    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
    ",sum[len+1][len+1]); 
        }
    }

    未优化代码

    #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
    ",ans); 
        }
    }
  • 相关阅读:
    OpenGL中glVertex、显示列表(glCallList)、顶点数组(Vertex array)、VBO及VAO区别
    OpenGL FrameBufferCopy相关Api比较(glCopyPixels,glReadPixels,glCopyTexImage2D,glFramebufferTexture2D)
    OpenGL渲染流程
    GPU大百科全书索引(有助于理解openGL工作流程)
    二进制配置文件为什么比json等配置文件效率高
    游戏开发中的矩阵初探
    Objective-C 30分钟入门教程
    cocos2dx骨骼动画Armature源码分析(三)
    cocos2dx骨骼动画Armature源码分析(二)
    linux中df和du查看磁盘大小不一致解决方法(转载)
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6753325.html
Copyright © 2011-2022 走看看