题意
题意不好写,就略过了。
( exttt{Data Range}:1leq nleq 10^5,1leq h_ileq 10^9)
题解
这神仙题差点把我给卡死。
首先考虑一次操作会对第 (i) 列方块的高度有什么影响,分三种情况讨论一下:
-
如果这列方块比左边一列的方块高,那么高度变为 (h_{i-1})。
-
如果这列方块比右边一列的方块高,那么高度变为 (h_{i+1})。
-
否则最上面一个方块总是要被消去的,高度变为 (h_{i}-1)。
三种情况取个最小值得到 (h_i=min(h_{i-1},h_{i+1},h_i-1))。
接下来考虑两次操作对 (h_i) 的影响,我们先算出 (h_{i-1},h_i,h_{i+1}) 一次操作后的高度,分别为:
[h_{i-1}=min(h_{i-2},h_{i},h_{i-1}-1),h_i=min(h_{i-1},h_{i+1},h_i-1),h_{i+1}=min(h_{i},h_{i+2},h_{i+1}-1)
]
再套一遍公式我们得到:
[h_i=min(h_{i-2},h_{i-1}-1,h_i-2,h_{i+1}-1,h_{i+2})
]
利用数学归纳法我们知道 (k) 次操作后有
[h_{i}=min(h_{i-k},h_{i-k+1}-1,cdots,h_{i}-k,cdots,h_{i+k})
]
于是我们的目标就是要求出对于每个 (i) 使得 (h_{i}=0) 的最小的 (k) 的最大值。
接下来我们单独考虑某个 (h_i),然后记 (k_j) 表示由 (h_j) 算出来的 (k) 值。
对于 (jin[i-k,i]) 来说 (h_i=h_j-j+i-k_j),即 (k_j=h_j-j+i)。
同理得到对于 (jin[i,i+k]) 来说 (k_j=h_j+j-i)。
由于现在 (i) 是恒定的,所以我们只需要求出 (h_j-j) 的前缀最小值和 (h_j+j) 的后缀最小值即可。这个可以使用线段树搞出来,注意几个小细节就好了。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51,inf=0x3f3f3f3f;
struct SegmentTree{
ll l,r,mn,mn2;
};
SegmentTree tree[MAXN<<2];
ll n,res=-inf;
ll h[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
#define ls node<<1
#define rs (node<<1)|1
inline void update(ll node)
{
tree[node].mn=min(tree[ls].mn,tree[rs].mn);
tree[node].mn2=min(tree[ls].mn2,tree[rs].mn2);
}
inline void create(ll l,ll r,ll node)
{
tree[node]=(SegmentTree){l,r,0,0};
if(l==r)
{
return (void)(tree[node].mn=h[l]-l,tree[node].mn2=h[l]+l);
}
ll mid=(l+r)>>1;
create(l,mid,ls),create(mid+1,r,rs),update(node);
}
inline ll query(ll l,ll r,ll node)
{
if(l>r)
{
return inf;
}
if(l<=tree[node].l&&r>=tree[node].r)
{
return tree[node].mn;
}
ll mid=(tree[node].l+tree[node].r)>>1;
return min(l<=mid?query(l,r,ls):inf,r>mid?query(l,r,rs):inf);
}
inline ll query2(ll l,ll r,ll node)
{
if(l>r)
{
return inf;
}
if(l<=tree[node].l&&r>=tree[node].r)
{
return tree[node].mn2;
}
ll mid=(tree[node].l+tree[node].r)>>1;
return min(l<=mid?query2(l,r,ls):inf,r>mid?query2(l,r,rs):inf);
}
#undef ls
#undef rs
int main()
{
n=read();
for(register int i=1;i<=n;i++)
{
h[i]=read();
}
create(0,n+1,1);
for(register int i=0;i<=n+1;i++)
{
res=max(res,min(query(0,i,1)+i,query2(i,n+1,1)-i));
}
printf("%d
",res);
}