题意:给定\(N(N<=10^5)\)个正整数的数列,求一个平均数最大且长度不小于m的连续的子段.输出子段和乘上1000之后的整数即可.
分析:实数域上的二分答案,每次直接二分平均数mid,然后令序列中的每个数减去该mid,对得到的新数列求前缀和sum,最后判定最大子段和是否非负即可.
至于如何求出新数列的最大子段和?用一个变量\(minn\)记录最小的\(sum[j]\),每次i递增时,与\(sum[i-m]\)取\(min\)来更新\(minn\),然后用\(sum[i]-minn\)更新最大子段和\(ans\)即可.
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read() {
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=100005;
int n,m,a[N];
double b[N],sum[N];
inline bool check(double mid){
for(int i=1;i<=n;++i)b[i]=a[i]*1.0-mid;
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+b[i];
double ans=-1e9,minn=1e9;
for(int i=m;i<=n;++i){
minn=min(minn,sum[i-m]);
ans=max(ans,sum[i]-minn);
}
if(ans>=0)return true;
else return false;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)a[i]=read();
double l=0.0,r=1e9,eps=1e-6;
while(r-l>eps){
double mid=(l+r)/2.0;
if(check(mid))l=mid;
else r=mid;
}
printf("%d\n",(int)(r*1000));
return 0;
}