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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章