题目大意是说,要求找到一个长度大于等于$F$的子段,使得这个子段内数字的平均值最大,求出这个最大值
解这道题分三步:
- 首先二分答案,也就是平均值$mid$
- 用原数组$A$减去平均值$mid$,得到新数组$B$,则问题转换为求$B$中是否存在一个长度大于等于$F$的子序列,使得子序列的和非负
- 用双指针$i,j$分别指向数组$B$的前缀和数组$S$,$i$从$0$开始往后扫描,$j$永远与$i$相隔$F$长度,$i$在移动过程中不断记录最小值,然后判断$sum[j]$是否大于等于这个最小值,如果大于,说明存在一个子序列和非负
import java.util.Scanner;
public class Main {
static int[] arr = new int[100010];
static double[] sum = new double[100010];
static int n, f;
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
n = cin.nextInt();
f = cin.nextInt();
arr = new int[n + 1];
for (int i = 1; i <= n; i++)
arr[i] = cin.nextInt();
double l = 0.0, r = 2000;
double eps = 1e-5;
while (r - l > eps) {
double mid = (l + r) / 2.0;
if (check(mid))
l = mid;
else
r = mid;
}
System.out.println((int)(r * 1000));
}
static boolean check(double mid) {
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + arr[i] - mid;
double min = 0;
for (int i = 0, j = f; j <= n; i++, j++) {
min = Math.min(min, sum[i]);
if (sum[j] >= min)
return true;
}
return false;
}
}