码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-08-03 16:23:12      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:printf   二分答案   mes   bool   技术分享   false   ++   hide   单调队列   

题意

给定一个长度为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 寻找段落(二分答案+单调队列)

标签:printf   二分答案   mes   bool   技术分享   false   ++   hide   单调队列   

原文地址:https://www.cnblogs.com/Xu-daxia/p/9414200.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!