【CF460C】 Present [二分 差分数组]

时间:2022-12-19 15:31:10

CF460C Present

一个长度为n 的序列a ,你有m 次操作的机会,每次操作是将其中连续的w个元素增加1 。最大化最终序列的最小值。

最小值最大 用二分

从左到右,如果某盆花小于二分值,将其以及后面的 w 盆花 +1 用线段树/差分 + 前缀和维护

当操作次数cnt>=m时不合法

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#include<algorithm> 
using namespace std;
#define Max(x,y) (x)>(y)?(x):(y)
#define Min(x,y) (x)<(y)?(x):(y)
#define ll long long
const int N=1e6+5,M=10000+5,inf=0x3f3f3f3f,P=9999973;
int n,m,w;
ll l=inf,r=0,a[N],d[N];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

bool check(ll lim){
    ll nw=0,cnt=0;
    for(int i=1;i<=n;++i){
        nw+=d[i];
        if(nw<lim){
            d[i]+=(lim-nw);
            cnt+=(lim-nw);
            if(i+w<=n) d[i+w]-=(lim-nw);
            nw+=(lim-nw);
        }
    }
    return cnt<=m;
}

int main(){
//    freopen("in.txt","r",stdin);
    rd(n),rd(m),rd(w);
    for(int i=1;i<=n;++i) rd(a[i]),l=Min(l,a[i]),r=Max(r,a[i]);
    r+=m+5;
    while(l<r-1){
        for(int i=1;i<=n;++i) d[i]=a[i]-a[i-1];
        ll mid=l+r>>1;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%lld",l);
    return 0;
}