码迷,mamicode.com
首页 > 其他好文 > 详细

CSAPC2008 skyline

时间:2018-10-17 00:58:30      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:scan   nbsp   using   结束   测试   偶数   print   int   ace   

一座山的山稜线由许多片段的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\n",s);
64 
65    return 0;
66 
67 }

 

CSAPC2008 skyline

标签:scan   nbsp   using   结束   测试   偶数   print   int   ace   

原文地址:https://www.cnblogs.com/zhou2003/p/9801610.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!