AcWing 102. 【Java】最佳牛围栏
原题链接
简单
作者:
tt2767
,
2019-12-16 00:35:45
,
所有人可见
,
阅读 923
// 第二次用java做的时候发现 没懂当初平均值的求法 和 为什么能用二分
// 1. 为什么能用二分? 结果必定为 [min ~ manx]; 所以可以校验所有可能结果的最大值,所以能从结果中二分答案
// 2. 怎么求最大子段平均值?
// 因为最小F段,每一段最小为1, 即扫描 F~N 的序列前缀和,求均值
// 因为本题转换为校验均值是否存在,可以把每一项都减去预期值,判断存在前缀和是否大于0
// 区间因为判断最大,所以区间开始一直记录最小值即可
// 3. 结果求最大子段,所以是右边界
import java.util.*;
public class Main{
void run(){
int n = jin.nextInt();
int f = jin.nextInt();
int[] block = new int[n+1];
for (int i = 1 ; i <= n ; i++){
block[i] = jin.nextInt();
}
int result = solve(n, f, block);
System.out.println(result);
}
int solve(int n, int f, int[] block){
double eps = 1e-5;
double l = 1e6;
double r = 1e-6;
for (int i = 1 ; i<= n ; i++){
l = Math.min(l, block[i]);
r = Math.max(r, block[i]);
}
while (r - l > eps){
double mid = (l + r) / 2;
if (isExistAvg(n, f, block, mid)) l = mid;
else r = mid;
}
return (int) (r * 1000);
}
boolean isExistAvg(int n, int f, int[] block, double avg){
double[] presum = new double[n+1];
for (int i = 1 ;i <= n ;i ++){
presum[i] = block[i] + presum[i-1] - avg;
}
double min = 0.0;
for (int i = f ; i <= n ;i ++){
min = Math.min(min, presum[i-f]); // 从0开始才是前f的和,又犯了一次错。。。。
if( presum[i] >= min ) return true;
}
return false;
}
private Scanner jin = new Scanner(System.in);
public static void main(String[] args) throws Exception {new Main().run();}
}