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; }
以上是关于luoguP1419 寻找段落(二分答案+单调队列)的主要内容,如果未能解决你的问题,请参考以下文章
[二分 分数规划 单调队列 最优平均值] P1419 寻找段落
[題解](二分答案/單調隊列)luogu_P1419尋找段落
BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列