luoguP1419 寻找段落(二分答案+单调队列)

Posted xu-daxia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP1419 寻找段落(二分答案+单调队列)相关的知识,希望对你有一定的参考价值。

题意

给定一个长度为n的序列a1~an,从中选取一段长度在s到t之间的连续一段使其平均值最大。(n<=100000)

题解

二分答案平均值。

judge时把每一个a[i]-mid得到b[i]

在b[i]中找到一段合法的串使其权值和最大。

当最大权值和大于等于0时则mid上移。

求最大权值和用单调队列就行。(预处理b[i]的前缀和sum[i],队列中记录当前位置可选区间的最小的sum[i])

技术分享图片
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=100000;
int n,a[N],q[N],s,t;
double ans,mid,l,r,sum[N],b[N];
bool judge(double pi){
    for(int i=1;i<=n;i++){
        b[i]=(double)a[i]-pi;
    }
//    cout<<pi<<endl;
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+b[i];
    //    cout<<sum[i]<<" ";
    }
//    cout<<endl;
    int head=1;
    int tail=0;
    for(int i=s;i<=n;i++){
        while(q[head]+t-1<i&&head<=tail)head++;
        while(sum[i-s]<sum[q[tail]]&&head<=tail)tail--;
        q[++tail]=i-s;
        if(head<=tail&&sum[i]-sum[q[head]]>=0)return true;
    }
    return false;
}
int main(){
    scanf("%d%d%d",&n,&s,&t);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    ans=-10000.0;
    l=-10000.0;r=10000.0;
    while(r-l>=1e-5){
        mid=(l+r)/2;
        if(judge(mid)){
            ans=mid;
            l=mid+1e-5;
        }
        else r=mid-1e-5;
    }
    printf("%.3lf",ans);
    return 0;
}
View Code

 

以上是关于luoguP1419 寻找段落(二分答案+单调队列)的主要内容,如果未能解决你的问题,请参考以下文章

题解P1419 寻找段落(二分+单调队列)难度⭐⭐⭐★

[二分 分数规划 单调队列 最优平均值] P1419 寻找段落

[題解](二分答案/單調隊列)luogu_P1419尋找段落

BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列

bzoj3316 JC loves Mkk 二分答案 单调队列

P3957 跳房子[二分答案][dp][单调队列]