zoukankan      html  css  js  c++  java
  • CSAPC2008 skyline

    一座山的山稜线由许多片段的45度斜坡构成,每一个片段不是上坡就是下坡。

                 *
        *   *  /
    *  /  //  
    //  /       

    在我们眼前的所见的任何宽度为n个单位的山稜形状,可以轻松地观察到所有山顶的位置。

    请问有多少种山稜线的形状,使得所有山顶的位置由左而右非递减呢?

    所有的山稜线都必须完整,也就是说左右两端都必须是高度为0的山脚,而且不能有任何山谷的位置隐没在地平线底下。

    输入说明

    输入仅包含一个数字nn一定会是偶数,因为会有相同片段数量的上坡以及下坡。

    输出说明

    请输出山顶位置由左而右非递减的山稜线形状总数。
    由于答案可能很大,你只要输出以十进位表示时,它的最后9位数即可。

    范例输入

    6

    范例输出

    4

    提示

    佔总分20%的测试数据中 n<=60
    佔总分40%的测试数据中 n<=200
    佔总分100%的测试数据中 n<=3000

    题解:

    动态规划

    dp[i][j]表示长度为i+j山稜最大高度为j时的方案数,那么它可以由以下两种状态转移过来。

    1)dp[i-1][j-1](在原图形的两侧分别加上一条线,如下图)

     

    2)之前已经存在了的最大高度为j的山峰,在左边补上高度比它小的山峰而形成的,如下图

    我们将情况2)通过一个前缀和数组sum[i][j]表示(表示长度不超过i+j且高度为j的方案数)

    那么状态转移方程即为:dp[i][j]=dp[i-1][j-1]+sum[i-2][j]

                          sum[i][j]=sum[i-1][j]+dp[i][j]

    为了保证合法则必须有(i+j) mod 2=0

    那么这题是不是结束了?并没有

    在情况2)中,我们直接加上了sum[i-2][j],这样做有什么问题吗?

    我们考虑下面的图

     

    对于左面新添加的山稜为了保证答案的合法,只能在它的旁边加上高度不超过当前最大高度的山稜即下面的转移是不合法的

     

    但是如果我们只是单纯的加上sum[i-2][j]是无法解决上面所提到的不合法的情况

    即:我们在转移完了之后,要减去一部分不合法的情况

    这些不合法的情况是:长度小于i-j,高度为j的所有山稜

    所以在转移完成之后需要将sum[i-j-j-1][j]减去即可

    最后答案:

    程序:

     1 #include <stdio.h>
     2 
     3 #include <iostream>
     4 
     5 using namespace std;
     6 
     7 const int maxd=1000000000;
     8 
     9  
    10 
    11 int dp[3001][3001]={0};
    12 
    13 int sum[3001][3001]={0};
    14 
    15  
    16 
    17 int main() {
    18 
    19    int n,i,j,s;
    20 
    21    dp[1][1] = 1;
    22 
    23    sum[1][1] = 1;
    24 
    25    for( i=2; i<=3000; i++ ) {
    26 
    27       for( j=1; j<i; j++ ) {
    28 
    29          if((i+j)%2==0) {
    30 
    31             dp[i][j] = (dp[i-1][j-1]+sum[i-2][j])%maxd;
    32 
    33             if(i-j-j-1>=0) {
    34 
    35                dp[i][j] = (dp[i][j]-sum[i-j-j-1][j])%maxd;
    36 
    37                if(dp[i][j]<0) dp[i][j]+=maxd;
    38 
    39             }
    40 
    41          }
    42 
    43          sum[i][j] = (sum[i-1][j]+dp[i][j])%maxd;
    44 
    45       }
    46 
    47       dp[i][i] = 1;
    48 
    49       sum[i][i] = 1;
    50 
    51    }
    52 
    53    scanf("%d",&n);
    54 
    55       s = 0;
    56 
    57       for( i=1; i<=n/2; i++ ) {
    58 
    59          s = (s+dp[n-i][i])%maxd;
    60 
    61       }
    62 
    63       printf("%d
    ",s);
    64 
    65    return 0;
    66 
    67 }
  • 相关阅读:
    vue相关坑
    jQuery上传文件按钮美化
    大屏幕数据可视化问题
    jquery实现点击页面空白处,弹框消失
    知识点
    js数字串传参时变科学计数法
    jQuery循环遍历取值
    如何判断一个弹框是打开还是关闭状态?
    js库写法
    React版本修改内容
  • 原文地址:https://www.cnblogs.com/encodetalker/p/9801610.html
Copyright © 2011-2022 走看看