原题链接
参考题解
题意概述
在给定的10个数中,连续选择大于等于6个数,求最大的可能的平均值。
为什么想到二分
题目中给了一个条件,每个数不会超过2000。给出的数据范围是10w,只能用O(nlogn)的算法,只能用二分了。可以给出的序列又没有单调性。所以想到在0-2000以内,二分答案。
还有一个trick,在代码的注释中说明了。真的牛!
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int cows[N];
double sum[N]; //前缀和数组
bool check(double avg)
{
for (int i = 1; i <= n; i++ )
sum[i] = sum[i-1] + cows[i] - avg;
double mins = 0;
// 因为i和j固定差m,所以可以用双指针
// 可以少一层for循环
// 这里还有一个优化,本来是要找i-m+1, 到i这几个数中
// 这几个数的和sum是不是>=0, 现在利用前缀和,即是否有sum[i] >= sum[i-m+1]
// 但是考虑到区间的长度选取还可以大于m,所以用双指针,mins记录最小值
// 太妙了
for (int i = m, j = 0; i <= n; i ++, j ++ )
{
mins = min(mins, sum[j]); // 记录前边的最小值
if (sum[i] - mins >= 0) return true;
}
return false;
}
int main()
{
cin >> n >> m;
double l = 0, r = 0;
for (int i = 1; i <= n; i ++ )
{
cin >> cows[i];
r = max(r, (double)cows[i]);
}
while (r - l > 1e-5)
{
double mid = (l + r) / 2;
if(check(mid)) l = mid; //找满足check条件的最大值,找尽可能右边的数
else r = mid;
}
printf("%d\n", (int)(r * 1000));
return 0;
}