最大均值【二分】

>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=sumiminj=1iL(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;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/112394134