
- 题目分析
这里讲一种不是二分的方法
考场上看完题之后我就只想到了枚举左右端点(太弱了)
然后我们可以很轻松的想到我们要堆出一个最高点的形状一定是以某两点为边界的一个金字塔形状
那我们可以用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(){
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;