C. Present(二分 + 扫描线)

题意: n盆花,浇k次水, 每次可使花高度 + 1, 每次可浇相邻的w盆,ai 表示 i-th盆花 的高度 问:当浇完m次后,最矮的一盆花最高可以使多少?

解题思路: 二分 + 扫描线, 由于高度最高10e9 + 10e5 ,最小1, 然后在 这范围内二分搜索。 

假设此时二分高度为 h=6, 每朵花初始高度依次如图所标。首先给第一朵花浇水,当前高度为2,还需要浇4天,temp = temp + 4,temp=4,但这四天只能对1,2,3起作用,对4不起作用,所以c[4] = -4,表示前面累积天数有四天对花4不起作用。给第二朵花浇水时,temp=4,已经浇了四天,而他只需要两天所以不用再浇,3也一样,c[2+w]=c[5]=0, c[3+w] = c[6]=0, 到4时temp = 4, 先消除前面影响,temp += c[4], temp = 0. 所以还需再浇4天,temp = 4,依次往后推。。。最后看总共浇水天数与剩下天数相比较 判定该高度是否可行。
————————————————

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define all(x) (x).begin(),(x).end()
#define de(a) cout<<#a<<" = "<<a<<endl
#define dd(a) cout<<#a<<" = "<<a<<" "
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
const ll mod = 1e9+7;
const int N = 2e5+20;
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define mes(p,b) memset(p,b,sizeof(p))
#define sz(x) int(x.size())
int n,m,w,a[N],l=INF,r=1e9+1e5;ll c[N];
bool check(int x){
    int t=1;ll y=m;ll temp=0;
    mes(c,0);
    rep(t,1,n){
        temp+=c[t];
        if(a[t]+temp<x){
            ll u=x-a[t]-temp;
            temp+=u;
            y-=u;
            c[t+w]-=u;
        }
    }
    return y>=0;
}
int main()
{
      ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>n>>m>>w;
    rep(i,1,n){
        cin>>a[i];
        l=min(a[i],l);
    }
    int ans=l;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    cout<<ans;
      return 0;
}

 

posted @ 2020-05-22 15:07  FZU_LH  阅读(199)  评论(0编辑  收藏  举报