最佳牛围栏

Posted maktub-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最佳牛围栏相关的知识,希望对你有一定的参考价值。

题目链接

 

题意

把一个长度为N的序列取出一段长度不小于F的子段,求平均值最大的子段的平均值。

思路

答案似乎不容易看出单调性。。。

换个思路, 一段序列减去平均值后得到的序列, 序列和一定为0.

如果减去的值小于平均值, 则序列和为正, 反之为负。

可以二分一个值, 然后减去这个值, 如果序列中长度不小于F的最大子段和为正, 说明平均值可以再大一些。。

单调性就可以看出来了: 二分值越大, 序列所有数减去二分值后得到的最大子段段和就越小。

关键便是快速判断最大子段和。

 

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<set>
#include<cmath>
using namespace std;

const int mx = 1e5 + 5;
const int inf = 1e9;

inline void fre() freopen("1.txt", "w", stdout); 

int n, L;
double a[mx], sum[mx];

inline bool check(double mid)
    sum[0] = 0;
    double x;
    for(int i = 1; i <= n; i++) x = a[i] - mid, sum[i] = sum[i-1] + x;
    double minn = inf, res = -inf;
    for(int i = L; i <= n; i++)
        minn = min(minn, sum[i-L]);
        res = max(res, sum[i] - minn);
     
    if(res >= 0) return 1;
    return 0;


int main()
    //fre();
    cin >> n >> L;
    double l = inf, r = 0;
    for(int i = 1; i <= n; i++) scanf("%lf", &a[i]), l = min(l, a[i]), r = max(r, a[i]);
    
    while(r - l > 0.000001)
        double mid = (l+r)/2;
        if(check(mid))  l = mid;
        else r = mid;
    
    
    printf("%d\n", (int)(r*1000));
    return 0;

 

以上是关于最佳牛围栏的主要内容,如果未能解决你的问题,请参考以下文章

102. 最佳牛围栏(二分)

102. 最佳牛围栏

最佳牛围栏(前缀和+二分)

最佳牛围栏

102. 最佳牛围栏

102. 最佳牛围栏二分 / 思维 不错