1. 程式人生 > >luoguP1419 尋找段落(二分答案+單調隊列)

luoguP1419 尋找段落(二分答案+單調隊列)

ons span 等於 algo 隊列 最大權值 str pac names

題意

給定一個長度為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 尋找段落(二分答案+單調隊列)