题目地址:
https://www.acwing.com/problem/content/description/104/
农夫约翰的农场由 N N N块田地组成,每块地里都有一定数量的牛,其数量不会少于 1 1 1头,也不会超过 2000 2000 2000头。约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大。围起区域内至少需要包含 F F F块地,其中 F F F会在输入中给出。在给定条件下,计算围起区域内每块地包含的牛的数量的平均值可能的最大值是多少。
输入格式:
第一行输入整数
N
N
N和
F
F
F,数据间用空格隔开。
接下来
N
N
N行,每行输入一个整数,第
i
+
1
i+1
i+1行输入的整数代表第
i
i
i片区域内包含的牛的数目。
输出格式:
输出一个整数,表示平均值的最大值乘以
1000
1000
1000再向下取整之后得到的结果。
数据范围:
1
≤
N
≤
100000
1≤N≤100000
1≤N≤100000
1
≤
F
≤
N
1≤F≤N
1≤F≤N
可以二分答案。先求前缀和数组 s s s,二分出答案 x x x后,其实就是问是否存在 0 ≤ i < j ≤ N 0\le i<j\le N 0≤i<j≤N使得 s j − s i j − i ≥ x , s j − j x ≥ s i − i x \frac{s_{j}-s_i}{j-i}\ge x,s_j-jx\ge s_i-ix j−isj−si≥x,sj−jx≥si−ix,在判断的时候可以遍历的时候维护 min i < j ( s i − i x ) \min_{i<j}(s_i-ix) mini<j(si−ix)即可。最后返回答案的时候要返回范围区间的右端点,因为求的是向下取整的结果。代码如下:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, f;
int a[N], s[N];
bool check(double x) {
double min_s = 0;
for (int i = f; i <= n; i++) {
double cur = s[i] - i * x;
min_s = min(min_s, s[i - f] - (i - f) * x);
if (cur >= min_s) return true;
}
return false;
}
int main() {
scanf("%d%d", &n, &f);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
s[i] = s[i - 1] + a[i];
}
double l = 0, r = 2000;
while (r - l > 1e-9) {
double mid = (l + r) / 2.0;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%d\n", (int)(r * 1000));
}
时间复杂度 O ( N log R ) O(N\log R) O(NlogR), R R R为搜索范围,空间 O ( 1 ) O(1) O(1)。