题意:给定(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
",(int)(r*1000));
return 0;
}