题意
给定一个长度为 (n) 的序列 (a),有 (m) 次操作,每次可以将 (a) 中的连续 (w) 个元素增加 (1),最大化最终序列的最小值。
( exttt{Data Range:}1leq wleq nleq 10^5,1leq mleq 10^5)
题解
咋一到数据结构题就缩卵呢,于是就理所当然的被神 ( exttt{x})( exttt{gzc}) 教育了 >_<
看到这种最小值最大这东西考虑二分答案,于是只需要对于二分出的答案 (x) 判定 (m) 次操作之后最小值是否不小于 (x)。
考虑贪心搞。如果 (a) 中存在一个值小于 (x) 我们就把他加到大于等于 (x) 即可,但是为了不浪费操作次数,我们可以直接加到 (x)。这里我的实现是以这个数为左端点来考虑。
但是有一些位置不可能成为长度为 (w) 的区间的左端点。这个时候考虑完前面所有的操作之后直接把 ([n-w+1,n]) 这个区间加上剩下的操作次数即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51;
ll n,m,w,l,r,mid,res;
ll x[MAXN],diff[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;
}
inline ll check(ll mid)
{
ll c=0,cur=m,p;
for(register int i=1;i<=n;i++)
{
diff[i]=x[i]-x[i-1];
}
for(register int i=1;i<=n-w+1;i++)
{
c+=diff[i];
if(cur>0&&c<mid)
{
p=min(cur,mid-c),diff[i]+=p,diff[i+w]-=p,cur-=p,c+=p;
}
}
diff[n-w+1]+=cur,diff[n+1]-=cur,c=0;
for(register int i=1;i<=n;i++)
{
c+=diff[i];
if(c<mid)
{
return 0;
}
}
return 1;
}
int main()
{
n=read(),m=read(),w=read(),l=0x3f3f3f3f,r=0x3f3f3f3f;
for(register int i=1;i<=n;i++)
{
x[i]=read(),l=min(l,x[i]);
}
while(l<=r)
{
ll mid=(l+r)>>1;
check(mid)?l=mid+1,res=mid:r=mid-1;
}
printf("%d
",res);
}