CodeForces 460C Present

题意

给定一个长度为 (n) 的序列 (a),有 (m) 次操作,每次可以将 (a) 中的连续 (w) 个元素增加 (1),最大化最终序列的最小值。

( exttt{Data Range:}1leq wleq nleq 10^5,1leq mleq 10^5)

题解

咋一到数据结构题就缩卵呢,于是就理所当然的被神 ( exttt{x})( exttt{gzc}) 教育了 >_<

db9tRU.jpg

看到这种最小值最大这东西考虑二分答案,于是只需要对于二分出的答案 (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);
}
原文地址:https://www.cnblogs.com/Karry5307/p/13584410.html