原题链接:最佳牛围栏
在开始前先牢骚一下就是马上要开始比赛了,小编这个蒟蒻很多算法也不会(线段树,lca啥的)但是也不准备新的算法了,就看着学过的老的算法多磨练一下吧 毕竟基础不牢地动山摇
这个题目呢,对于基础算法是一个非常好的题目
看到两个字眼 :至少需要F块地 ,最大值是多少 这么一看来的话就满足了二分性质:
1,满足单调性
2,满足边界性
3,最大值的最小值,最小值的最大值
对于单调性,我们对于答案二分(答案永远都是单调的)
所以我们就可以直接开搞
这里需要注意的是 我们二分的是一个Double类型 那么之前的模板可能就需要发生变化
while(r-l>1e-5)
{
double mid = (r+l)/2;//这里不能运用位运算
if(!check(mid)) l = mid;//没有+1或者-1这种操作,因为double精度问题
else r = mid;
}
那么我们的二分模板就写出来了,难点在于check函数!!
所以check函数如下
bool check(double mid){
//注意这里的前缀 是减去mid的前缀 这样的好处可以用加减法直接判断此值是否大于平均值
for(int i = 1;i<=n;i++) qz[i] = qz[i-1]+arr[i]-mid;
double minv = 0;
//这里用到双指针,锁定区间在F
for(int i = 0,j=m;j<=n;i++,j++){
//minv可以直接保证区间长度>=F并且能取到最优
minv = min(minv,qz[i]);
//当这个前缀的值大于等于0时,说明区间内每个值的和的均值大于等于0,直接返回
if(qz[j] - minv>=0) return true;
}
return false;
}
最后合并代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
double arr[N];
double qz[N];
int n,m;
double l,r;
bool check(double mid){
for(int i = 1;i<=n;i++) qz[i] = qz[i-1]+arr[i]-mid;
double minv = 0;
for(int i = 0,j=m;j<=n;i++,j++){
minv = min(minv,qz[i]);
if(qz[j] - minv>=0) return true;
}
return false;
}
int main(){
cin>>n>>m;
for(int i = 1;i<=n;i++){
cin>>arr[i];
r= max(arr[i],r);
}
while(r-l>1e-5){
double mid = (l+r)/2;
if(!check(mid))r = mid;
else l = mid;
}
cout<<(int)(r*1000);
}