2022 Hubei Provincial Collegiate Programming Contest G. Brick(gym103729)

大意

给出底层高度,用1*2的砖块将总形状铺成等高矩形,使得高度最小(不能放在外面)

题解

奇妙做法

当高度同奇偶时显然x可以的话x+2也可以,直接加一层竖的,所以首先分奇偶二分高度

有解的必要条件1是,把矩形黑白方格染色之后未填的黑=白(一个1*2刚好覆盖1黑1白)

然后从左往右放砖块,可以感受一下发现把当前列尽量往上拉是最优的

比如二分ans=10,初始h=4,3,2,1,1

那么往右扫过去可以依次拉到10,9,8,7高度;接下来把h[5]拉到7之后又可以整体横着放一波,变成10,10,10,9,8的阶梯

于是维护阶梯的最下端高度hnow,当h[i]和hnow不同奇偶时可以拉到hnow-1,否则拉到hnow之后再整体往上拉变成hnow+1

这样从左往右知道hnow<h[i],此时无论如何也无法拉成阶梯状,记录终止位置i

然后求出从右往左的终止位置j,若j<i则有解
感受一下就是可以从左往右和从右往左拉出两个阶梯,然后剩下由于必要条件1剩下一定合法(


最后再打表感受一下发现ans不超过max(h[i])+1,所以不用二分了(

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,mx;
int h[200001];
ll L,R,Mid,ans;

bool pd(ll t)
{
	int i,j;
	ll sum=0,h1=t,h2=t;
	if (t<mx) return 0;
	
	fo(i,1,n)
	{
		if (i&1)
		{
			if ((t-h[i])%2==1)
			++sum;
		}
		else
		{
			if ((t-h[i])%2==1)
			--sum;
		}
	}
	if (sum) return 0;
	
	fo(i,1,n)
	{
		if (h1>=h[i])
		{
			if ((h1-h[i])%2==0)
			h1=min(h1+1,t);
			else
			--h1;
		}
		else
		break;
	}
	fd(j,n,1)
	{
		if (h2>=h[j])
		{
			if ((h2-h[j])%2==0)
			h2=min(h2+1,t);
			else
			--h2;
		}
		else
		break;
	}
	
	if (j<i) return 1;
	else return 0;
}

int main()
{
//	freopen("G.in","r",stdin);
	scanf("%d",&n);
	fo(i,1,n) scanf("%d",&h[i]),mx=max(mx,h[i]);
	
//	printf("%d\n",pd(10));
	
	ans=2000000000;
	L=1,R=2000000000;
	while (L<R)
	{
		Mid=(L+R)/2;
		if (!pd(Mid*2-1))
		L=Mid+1;
		else
		R=Mid;
	}
	ans=min(ans,L*2-1);
	L=1,R=2000000000;
	while (L<R)
	{
		Mid=(L+R)/2;
		if (!pd(Mid*2))
		L=Mid+1;
		else
		R=Mid;
	}
	ans=min(ans,L*2);
	
	if (ans==2000000000) ans=-1;
	printf("%lld\n",ans);
}
posted @ 2023-09-09 20:02  gmh77  阅读(55)  评论(0编辑  收藏  举报