AcWing - 最佳牛围栏(二分、前缀和)
题目链接
题目要求我们求出满足条件的最大值,因为\(f\)的长度不是固定的,所以如果直接求解的话,非常麻烦。但是,如果我们用二分判定答案的话,问题就变得简单了。但是二分必须要区间具有单调性,我们怎么让区间具有单调性呢?对于一个平均值,如果它偏大的话,那么这个区间里面任意长度的序列的平均值都取不到这个值,换句话说,如果让他们的平均值与二分的平均值比较,结果肯定是负的,同理,对于一个偏小的平均值,一定可以在序列里面找到一个连续子序列,它的平均值大于二分的平均值。
但是这时候又会有一个问题出现了,我们怎么在最短的时间内找到一个序列判断它的平均值是否大于\小于我们二分的平均值呢?这里,我们不需要把所有的可能全都枚举出来。我们先让整个序列全都减去我们二分的平均值(实现起来并不需要这么麻烦,这里只是方便理解),然后我们所要做的就是找一个连续子区间,它的区间和大于\(0\)。这个问题还能进一步转化为我们找一个从\(1\)开始以\(k\)结尾的区间(区间长度大于\(f\),而且\(k\leq n\)),然后判断在这个区间内有没有一个以\(l\)结尾的区间(\(l\leq k-l\)),这样的话,我们只要对这个区间做一个前缀和来处理一下就行了
//https://www.cnblogs.com/shuitiangong/
#include<set>
#include<map>
#include<list>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define endl '\n'
#define rtl rt<<1
#define rtr rt<<1|1
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define zero(a) memset(a, 0, sizeof(a))
#define INF(a) memset(a, 0x3f, sizeof(a))
#define IOS ios::sync_with_stdio(false)
#define _test printf("==================================================\n")
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<ll, ll> P2;
const double pi = acos(-1.0);
const double eps = 1e-7;
const ll MOD = 1000000009;
const int INF = 0x3f3f3f3f;
template<typename T> void read(T &x){
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
const int maxn = 1e5+10;
double cow[maxn];
int n, f;
bool checker(double mid) {
double minn = 0;
for (int i = f; i<=n; ++i) {
if (cow[i-f]-mid*(i-f) < minn) minn = cow[i-f]-mid*(i-f);
if (cow[i]-mid*i>minn || fabs(cow[i]-mid*i-minn)<eps) return true;
}
return false;
}
int bysh() {
double l = 1.0, r = 2000.0;
while(l+eps<r) {
double mid = (l+r)/2.0;
if (checker(mid)) l = mid;
else r = mid;
}
return int(r*1000);
//return int((l+eps)*1000); 上面和这个都行,但是下面这个不行
//return int(l*1000); 因为精度问题,l可能小于我们取到的值
}
int main(void) {
while(~scanf("%d%d", &n, &f)) {
for (int i = 1; i<=n; ++i) {
scanf("%lf", &cow[i]);
cow[i] += cow[i-1];
}
printf("%d\n", bysh());
}
return 0;
}