题目1:http://ybt.ssoier.cn:8088/problem_show.php?pid=1434
思路:二分加DP。判断mid比答案大还是小,就要用到"前缀存压缩"的方法。把数列的每个值都减去这个平均值,如果这种操作之后的区间内数字和大于等于0,说明这个数列存在比mid还大的平均值。
!注意:区间长度要大于等于L。
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100001];
double b[100001],sum[100001];
bool check(double mid){
int i;
for(i=1;i<=n;++i){
b[i]=a[i]*1.0-mid;//减去假定的平均值
}
for(i=1;i<=n;++i){
sum[i]=sum[i-1]+b[i];//压缩
}
double ans=-1e9,minn=1e9;
for(i=m;i<=n;++i){//开始表演
minn=min(minn,sum[i-m]);
ans=max(ans,sum[i]-minn);
}
if(ans>=0){//区间和大于等于0
return 1;//打回“真”,肯定还能有更大的
}
return 0;//认怂
}
int main(){
int i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i){
scanf("%d",&a[i]);
}
double l=0.0,r=1e9,q=1e-6;//注意,q的精度不能太高
while(r-l>q){
double mid=(l+r)/2.0;//正常操作
if(check(mid)){//区间和真的大于等于0了
l=mid;//往前推,我还能再大一点
}
else{//否则
r=mid;//认怂
}
}
printf("%d\n",(int)(r*1000));//要求是一千倍
//那个(int)是为了消除遗留的小数
return 0;
}