CF460C Present

博客食用更佳

思路

二分

一看最小的最大就是二分了

线段树

二分时判断是否成立时用到
每次扫一遍,当有树高度小于mid时,增加这w个树的高度
区间修改单点查询

树状数组

区间修改单点查询可以用树状数组差分实现
于是我偷懒用了树状数组
可以封装使代码更简洁

代码

#include<bits/stdc++.h>
#define ll long long
#define N 100010
#define lowbit(x) x&-x
using namespace std;
int n,m,w;
ll a[N];
struct BIT{
    ll c[N];
    void _add(int x,ll v){
        while(x<=n){
            c[x]+=v;
            x+=lowbit(x);
        }
    }
    void add(int l,int r,ll v){
        _add(l,v);
        _add(r+1,-v);
    }
    ll operator[](int x){
        ll ans=0;
        while(x>0){
            ans+=c[x];
            x-=lowbit(x);
        }
        return ans;
    }
    BIT(){memset(c,0,sizeof(c));for(int i=1;i<=n;i++)_add(i,a[i]-a[i-1]);}
};//封装
bool check(ll ht){//1::not enough 2::too large
    BIT b;
    ll cm=m;
    for(int i=1;i<=n;i++){
        ll x=b[i];
        if(x<ht){
            if(i>=n-w+2){
                b.add(n-w+1,n,ht-x);
            }
            else{
                b.add(i,i+w-1,ht-x);
            }
            cm-=ht-x;
        }
    }
    if(cm>=0)return 1;
    else return 0;
}//判断是否合法
int main(){
    cin>>n>>m>>w;
    ll l=1,r=0,mid;
    for(int i=1;i<=n;i++)cin>>a[i],r=max(a[i],r),l=min(a[i],l);
    r+=m+1; 
    while(l<r-1){
        mid=(l+r)>>1;
        if(check(mid))l=mid;
        else r=mid;
    }//二分
    cout<<l;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/bossbaby/p/10951787.html