一个长度为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; }