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; }