>Link
ybtoj最大均值
>解题思路
考虑二分答案(最大平均数),将 a a a序列减去当前二分值存到 b b b序列中,这是问题就转换为“长度不小于L且区间和不小于0的序列”
定义 s u m i sum_i sumi为前 i i i位的和, m a x i max_i maxi为前 i i i位中长度不小于L且区间和最大的那个值,
运用前缀和的思想, m a x i = s u m i − m i n j = 1 i − L ( s u m j ) max_i=sum_i-min^{i-L}_{j=1}(sum_j) maxi=sumi−minj=1i−L(sumj)
因为 i i i每累加1, j j j的范围就累加1,所以我们只需要每次记录下当前最小的 s u m j sum_j sumj,就可以 O ( n ) O(n) O(n)计算出 m a x i max_i maxi
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 100010
#define inf 1 << 30
#define db double
using namespace std;
const db eps = 0.00001;
int n, m;
db a[N], sum[N], l, r, mid;
bool check (db x)
{
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i] - x;
db minn = inf, maxn = -inf;
for (int i = m; i <= n; i++)
{
minn = min (minn, sum[i - m]);
maxn = max (maxn, sum[i] - minn);
}
return maxn >= 0;
}
int main()
{
scanf ("%d%d", &n, &m);
l = inf;
for (int i = 1; i <= n; i++)
{
scanf ("%lf", &a[i]);
l = min (l, a[i]), r = max (r, a[i]);
}
while (r - l > eps)
{
mid = (l + r) / 2;
if (check (mid)) l = mid;
else r = mid;
}
printf ("%d", (int)floor(r * 1000));
return 0;
}