NOIP模擬 積木大賽

在這裏插入圖片描述

  • 題目分析
    這裏講一種不是二分的方法
    考場上看完題之後我就只想到了枚舉左右端點(太弱了)
    然後我們可以很輕鬆的想到我們要堆出一個最高點的形狀一定是以某兩點爲邊界的一個金字塔形狀
    那我們可以用l,r表示左右端點
    l,r均從一開始,當目前l,r堆出的三角形需要的積木塊數小於總塊數,就r++反之則l++
    然後大數據測一波發現30s。。。
    那考慮優化
    我們發現這樣一個優化:一塊旁邊的最多比它高一的高度,如果本身就比它高,那不就可以省略嗎?
    那我們判斷h[l] + (i - l) <= h[i],如果符合我們就直接從l跳到i去
    r同理得到h[r] + (r - i) < h[i]
    這樣可以節省大波時間(雖然相對二分也很慢)
    下面給出代碼
#include<bits/stdc++.h>
using namespace std;
const int Maxn=1e5+5;
int n,m;
int h[Maxn];
int now[Maxn];
long long sum[Maxn];
int l = 1,r = 3;
int ans;
void in(int &x)
{
	x = 0;
	int f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		x = (x << 3) + (x << 1) + c - '0';
		c = getchar();
	}
	x *= f;
	return;
}
void out(int x)
{
	if (x < 0)
	{
		x = -x;
		putchar('-');
	}
	if (x > 9)
	{
		out(x / 10);
	}
	putchar(x % 10 + '0');
}
long long fill(int l,int r)
{
	long long need=0;
	for (int i = l; i <= r; i++)
	{
		now[i] = h[i];
	}
	while (l + 1 < r)
	{
		while (now[l] < now[r])
		{
			now[l + 1] = now[l] + 1;
			need += now[l + 1] - h[l + 1];
			l++;
		}
		while (now[l] > now[r])
		{
			now[r - 1] = now[r] + 1;
			need += now[r - 1] - h[r - 1];
			r--;
		}
		while (l + 1 < r && now[l] == now[r])
		{
			now[l + 1] = now[l] + 1;
			need += now[l + 1] - h[l + 1];
			l++;
			now[r - 1] = now[r] + 1;
			need += now[r - 1] - h[r - 1];
			r--;
			if (l == r && now[l] > h[l])
			{
				need -= now[l] - h[l];
			}
		}
	}
	if (need <= m)
	{
		ans = max(ans,now[l]);
	}
	return need;
}

int main(){
//	freopen("block.in","r",stdin);
//	freopen("block.out","w",stdout);
	in(n);
	in(m);
	for(int i = 1; i <= n; i++)
	{
		in(h[i]);
		sum[i] = sum[i - 1] + h[i];
		if (ans < h[i]) ans = h[i];
	}
	while(l <= n && r <= n)
	{
		if (l + 2 > r) r = l + 2;
		for (int i = l; i <= r; i++)
		{
			while (h[l] + (i - l) <= h[i] && l < i)
			{
				l++;
			}
			while (h[r] + (r - i) < h[i] && r < n)
			{
				r++;
			}
		}
		if (l+2 > r) r = l + 2;
		if(fill(l,r)<=m)
			r++;
		else
			l++;
	}
	out(ans);
	return 0;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章