2017 10 01国庆节大礼包 四校联考

1.积木大赛

(block.pas/c/cpp)

【问题描述】

为了庆祝国庆,厦门一中举办了一年一度的“积木大赛”。

在2013年NOIP大赛中,夏夏同学己经搭建了宽度为n的大厦,其中第i块高度为hi。今年比赛的内容是对其NOIP2013搭建大厦进行扩建,使用的材料也都是体积为1正方体积木。

今年搭建的规则是:如果要在某一个位置上放一个积木,必须满足它的左下、下方、右下都有积木(用二维坐标a表示,如果要在a[i,j]位置放积木,那么a[i-1,j-1]、a[i,j-1]、a[i+1,j-1]必须要有积木)。

  如果搭的积木大厦越高,夏夏同学就会觉得越有成就感,现有m个积木,问你能搭建的最大高度是多少?

【输入】

第一行两个用空格隔开的整数n和m,分别表示己搭好的宽度和可以使用的积木数量。

后面有n行,每行一个整数hi表示己搭建的第i列积木的高度。

【输出】

一个整数,表示能搭建的最大高度。

【输入输出样例】

样例1

样例2

block.in

block.out

block.in

block.out

8 4

3

4

2

1

3

3

2

4

5

3 100

3

3

3

4

【数据说明】

    30%的数据满足:n<=10;m<=1000。

    50%的数据满足:n<=100;m<=1000,000。

70%的数据满足:n<=1000;m<=10,000,000。

    80%的数据满足:n<=10,000;m<=100,000,000。

100%的数据满足:n<=100,000;m<=1000,000,000。

 

 

题解:

算法一:对于50%的数据:

①从高到低枚举每一个高度看是否能达到, 时间复杂度O(n);

②对于每一个高度,枚举最高点在哪一列,时间复杂度O(n);

③从当前枚举的最高列往两边递减判断是否合法,时间复杂度O(n);

总时间复杂度O(n3)。

 

算法二:对于70%的数据:

在算法一中的第二步求高度时,使用二分答案,时间复杂度降为O(logn)。总时间复杂度为O(n2logn)。

 

算法三:100%的数据:

  对于第二步和第三步,根据单调性,我们用L[i]表示在高度为H时第I列达到高度H时最左端的位置,R[i]为最右端的位置。通过O(n)的时间得到L,R,总的时间复杂度为O(nlogn)。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cmath>
 4 #include <stdio.h>
 5 #include <string>
 6 #include <string.h>
 7 #include <numeric>
 8 using namespace std;
 9 int a[500001];
10 long long s[500001];
11 int l[500001];
12 int r[500001];int n,m;
13 int read()
14 {
15     char ch=getchar();
16     int t=0;
17     int f=1;
18     while(ch>'9' || ch<'0')
19       {ch=getchar();}
20     while(ch>='0' && ch<='9')
21       t=(t<<3)+(t<<1)+ch-'0',ch=getchar();
22     return t;
23 }
24 bool check(int h)
25 {
26     memset(l,0,sizeof l);memset(r,63,sizeof r);
27     int i;
28     int inf=r[0];
29     for (i=1;i<=n;i++)
30         if (i+h-a[i]<=n)
31             l[i+h-a[i]]=i;
32     for (i=n;i>=1;i--)
33         if (i+a[i]-h>0)
34           r[i+a[i]-h]=i;
35     
36     for (i=1;i<=n;i++)
37       l[i]=max(l[i],l[i-1]);
38     for (i=n;i>=1;i--)
39       r[i]=min(r[i],r[i+1]);
40     for (i=1;i<=n;i++)
41       {
42           if (!l[i] || inf==r[i]) continue;
43           if((1ll*(a[l[i]]+h)*(i-l[i]+1)>>1)+(1ll*(a[r[i]]+h-1)*(r[i]-i)>>1)-(s[r[i]]-s[l[i]-1]) <= m)
44             return 1;
45       }
46     return 0;
47 }
48 int main()
49 {
50     
51     n=read();
52     m=read();
53     int i;int l=0;
54     for (i=1;i<=n;i++)
55       a[i]=read(),s[i]=s[i-1]+a[i],l=max(l,a[i]);
56     int r=2000000000;
57     int mid;
58     while(l<r)
59       {
60           mid=l+((r-l)>>1);
61           if (check(mid))
62             l=mid+1;
63           else r=mid;
64       }
65     printf("%d
",l-1);
66     return 0;
67 }
block
原文地址:https://www.cnblogs.com/yz12138/p/7619708.html