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;
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12718508.html