二分求区间长度限制的区间平均值最大值

原题链接

题目分析

本题我们解决的是,在限制了区间长度时,求区间最大的平均值。

对于这个问题,第一个思路是最朴素的思路,枚举区间长度,再以此枚举每一个区间,区间内和的问题可以由前缀和来解决。但是这样,我们的时间复杂度就是趋近于n方的,肯定不行。随后想到是否可以用二分来解决这个问题。

既然考虑使用二分,那就要考虑对什么进行二分,是否又具有二分的属性。

二分的属性:是考虑枚举mid时,是否是一般满足,而一半不满足的

我们这里枚举的是平均值,平均值的区间是[0,MAX],这里的MAX指的是,区间内最大的那个数。

这里也是符合二分的特点的,枚举mid时,我们只需要判断是否存在一个平均值大于等于mid的,则说明答案在右边,不存在则说明答案在左边,符合二分要求。因此可以进行二分

check函数

确定了使用二分后,我们进行check函数的书写。

根据题意,我们需要找的是,一段长度大于等于F的区间,使它的平均值最大。

那我们的check函数,就要判断是否有一个长度大于等于F的区间,使其平均值大于我们枚举的mid

这里我们进行了三步优化:

  1. 首先,我们考虑到要计算区间的平均值的最大值跟我们枚举的mid比较,则,我们可以将所有数字全部减去我们枚举的mid,此时在对区间进行求和时,若是大于0,则证明,这个区间的平均值大于我们枚举的mid。

    即,我们利用区间和,来完成了枚举区间的平均值与我们枚举的mid的比较

  2. 第二点优化,既然我们要算区间和了,那就一定是要用前缀和了,这样就能用o(1)的时间求出区间和。

  3. 最后,我们想到,枚举区间时,我们按照确定每一个区间的右端点来枚举区间长度的方法来枚举区间。这样我们的区间左端点可取范围是[1,r-k+1]。我们算区间和时,是s[r]-s[l-1],因此,我们只需s[l-1]最小即可。同时因为我们的区间是不断后移的,我们可以为欧虎一个mins来维护我们能减去的最小值。

ACcode

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
double a[N],s[N];
int n,F;
bool check(double mid)
{
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i]-mid;
    double mins=0;
    for(int i=F;i<=n;i++)
    {
        mins=min(mins,s[i-F]);
        if(s[i]>=mins) return 1;
    }
    return 0;
}

int main()
{
    scanf("%d%d",&n,&F);
    double l=0,r=0;
    for(int i=1;i<=n;i++) 
    {
        scanf("%lf",&a[i]);
        r=max(r,a[i]);
    }
    
    while(r-l>=1e-5)
    {
        double mid = (l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    
    printf("%d\n",(int)(r*1000));
    return 0;
}

二分求区间长度限制的区间平均值最大值

上一篇:使用pynput模拟键盘、鼠标操作


下一篇:numpy 库