版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
一、内容
题意:给定正整数数列A,求一个平均数最大的、长度不小于L的字段。
二、思路
- 我们选取一段连续的数的和 sum / 土地数量 n = ans 转化为 sum = ans * n
- 我们把每一个数都减去ans(二分枚举的答案),然后转化为求某一段不小于L的区间最大和。
- 我们用一个min_val记录每次前面区间的最小值,这样我们只需要让sum[i] - min_val即可获取区间最大和了。
三、代码
#include <cstdio>
#define min(a, b) (a > b ? b : a)
#define max(a, b) (a > b ? a : b)
const int N = 1e5 + 5;
int n, f;
double a[N], b[N], sum[N];
int main() {
scanf("%d%d", &n, &f);
for (int i = 1; i <= n; i++) {
scanf("%lf", a + i);
}
double l = 0, r = 2000;
double eps = 1e-5;
while (r - l > eps) {
double mid = (l + r) / 2;
//所有数减去mid
for (int i = 1; i <= n; i++) {
b[i] = a[i] - mid;
}
//求前缀和
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + b[i];
}
double ans = -1e10;
double min_val = 1e10;
for (int i = f; i <= n; i++) {
min_val = min(min_val, sum[i - f]);
ans = max(ans, sum[i] - min_val);
}
if (ans >= 0) {
l = mid;
} else {
r = mid;
}
}
//由于653.666 答案是653因为654就不满足结果了所以必须向下取整
printf("%d\n", int(r * 1000));
return 0;
}