解析:
显然这个答案是满足二分性质的。
然而二分后怎么验证?考虑最大连续子段和的做法。
将原序列减去二分的平均值,直接最大连续子段和。
我们维护一下当前位置至少前
F
F
F个位置的最大子段和,遇到小于0说明这段的平均数小于当前二分答案。而且会为接下来的序列的平均数拖后腿,不如直接弃掉。
代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static
inline
ll getint(){
re ll num=0;
re char ch;
for(ch=gc();!isdigit(ch);ch=gc());
for(num=0;isdigit(ch);ch=gc())num=(num<<1)+(num<<3)+(ch^48);
return num;
}
int N,F;
double a[100002];
double sum[100002];
double l=100000000,r=0;
inline
bool check(double x){
double f=sum[F-1]-(F-1)*x;
for(int re i=F;i<=N;++i){
f=f+a[i]-x;
f=max(f,sum[i]-sum[i-F]-x*F);
if(f>-1e-6)return true;
}
return false;
}
int main(){
while(~scanf("%d%d",&N,&F)){
sum[0]=0;
for(int re i=1;i<=N;++i){
scanf("%lf",&a[i]);
sum[i]=a[i]+sum[i-1];
l=min(l,a[i]);
r=max(r,a[i]);
}
while(l+1e-6<=r){
double mid=(l+r)/2;
if(check(mid))l=mid;
else r=mid;
}
int x=r*1000;
printf("%d\n",x);
}
return 0;
}