农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于 1 头,也不会超过 2000 头。
约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大。
围起区域内至少需要包含 F 块地,其中 F 会在输入中给出。
在给定条件下,计算围起区域内每块地包含的牛的数量的平均值可能的最大值是多少。
输入格式
第一行输入整数 N 和 F,数据间用空格隔开。
接下来 N 行,每行输入一个整数,第 i+1 行输入的整数代表第 i 片区域内包含的牛的数目。
输出格式
输出一个整数,表示平均值的最大值乘以 1000 再 向下取整 之后得到的结果。
数据范围
1≤N≤100000
1≤F≤N
输入样例:
10 6
6
4
2
10
3
8
5
9
4
1
输出样例:
6500
解题思路:
这道题要我们找到长度不小于f的一段数列,并使这段数列的平均值最大,我们可以从最小值到最大值进行二分,如果中间的值能找到一个满足条件,则把中间值赋值给最小值;否则把中间值赋值给最大值,继续二分直到误差足够小可以忽略。
我们在判断中间值有没有可能是平均值时,我们先把每个数都减去平均值就能看出原来的数与平均值的大小,再采用前缀和计算,sum[i] = sum[i-1] + a[i] - avg,要保证一段数列的长度不小于f,我们可以用双指针来控制,i从0开始,j从f开始,i,j一起动,我们要找到一个满足sum[j] - sum[i] >=0(也就是从a[i+1]到a[j]的和大于0,即这一段的平均值大于avg),这个sum[i]要尽可能小,所以我们就取sum[i]的最小值minv,如果找到一个满足条件sum[j] - minv >=0即sum[j] >=minv,就说明至少要一段数列满足这个平均值,因为平均值要最大,所以我们从这个平均值到最大值继续二分。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int a[N],n,f;
double sum[N];
bool check(double avg) { //判断这个数有没有可能是平均值
for(int i=1; i<=n; i++)
sum[i]=sum[i-1]+a[i]-avg; //计算前缀和
double minv=0;
for(int i=0,j=f; j<=n; i++,j++) {
minv=min(minv,sum[i]); //找到最小值
if(sum[j]>=minv) return 1;
}
return 0;
}
int main() {
cin>>n>>f;
for(int i=1; i<=n; i++)
cin>>a[i];
double l=1,r=2000; //题意说明牛的数量在1~2000中
while(r-l>1e-5) { //开始二分
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%d\n",int(r*1000)); //这个平均值要尽可能大,所以是右端点
return 0;
}