6562. 【GDOI2020模拟4.15】楼房搭建(building)
题目描述
小 H 是一个建筑师,他接到了一个任务——按照计划图搭建一排楼房。计划图上从左到右
给出了 n 个非负整数,对于第 i 个数 h i ,它表示在 i 这个位置搭建出来的楼房的高度不能小于h i 。
小 H 搭建楼房的方式也很特别。在每一时刻,它总可以让相邻的两个楼房分别增高 1 个单
位和增高 2 个单位。具体地,对于任意的 i(1 ≤ i < n),每一时刻他可以有以下两种搭建的方法:
\1. 让 i 位置上的楼房的高度 +2,同时让 i + 1 位置上的楼房 +1。
\2. 让 i 位置上的楼房的高度 +1,同时让 i + 1 位置上的楼房 +2。
小 H 想知道最快需要多少时间,搭建出来的这一排楼房才能满足计划图的要求?
n,hi<=10^6
题解
贪心苦手表示很淦
考虑一个假的贪心:每次对当前的进行+2+1,如果最后剩下一个就+1+2
这样显然是假的,考虑反悔操作:
①+2+1->2*(+1+2),等价于用1的代价把i+1位+3
②+3->(+1+2)+(+2+1),等价于用1的代价把i+1位+3(前提是至少有一个+3)
②+3->3*(+1+2),等价于用2的代价把i+1位+6(前提是至少有一个+3)
维护当前可以的最多+3次数,判断一下剩余情况与剩余的奇偶即可
并不需要考虑+3具体是怎么得到的,如果要拆的话等于把之前的一系列组合操作拆开
感受一下
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;
int n,i,j,k,l,x,X,cnt,sum;
ll ans;
int main()
{
freopen("building.in","r",stdin);
#ifdef file
freopen("building.out","w",stdout);
#endif
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&x);x-=X;
if (x<=0) {X=cnt=0;continue;}
if (cnt*3>=x)
X=(x%3==0)?0:(3-x%3),ans+=(x/3)+(x%3>0),cnt=(x/3)*2+(x%3==2);
else
X=((x-cnt*3)/2)+(x-cnt*3)%2*2,x-=cnt*3,ans+=cnt+(x+1)/2,cnt=cnt*2+x/2;
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}