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\n",l-1); 66 return 0; 67 }block
2017 10 01國慶節大禮包 四校聯考