P1419 寻找段落 单调队列+二分
题意:给出n个数,让我们求出一个最大的平均值
求平均值的区间只能在【s,t】这样的一个范围内选取
假如【3 ,4】,则表明可以选择一个区间大小为3或者4的,而不能选择其他大小
思路:
首先二分答案,即:二分最大平均值。
我们将a全部减去mid,问题转化为判断是否存在一个长度在s~t范围内的区间它的和为正,如果有说明还有更大的平均值。
用前缀和和单调队列维护。
然后用单调队列求出sum[i]-min(sum[i-t]~sum[i-s]),然后判断是否大于0即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 int a[maxn]; 5 double sum[maxn];int q[maxn]; 6 int n,s,t; 7 bool check(double mid) 8 { 9 for(int i=1;i<=n;i++) 10 sum[i]=sum[i-1]+double(a[i])-mid; 11 int head=1,tail=0,q[maxn]; 12 for(int i=s;i<=n;i++){ 13 while(head<=tail&&sum[q[tail]]>sum[i-s]) tail--; 14 q[++tail]=i-s; 15 while(head<=tail&&q[head]<i-t) head++; 16 if(head<=tail&&sum[i]-sum[q[head]]>=0) return 1; 17 } 18 return 0; 19 } 20 int main() 21 { 22 scanf("%d%d%d",&n,&s,&t); 23 for(int i=1;i<=n;i++){ 24 scanf("%d",&a[i]); 25 } 26 double L=-10000; 27 double R=10000; 28 while(R-L>=1e-5){ 29 double mid=(L+R)/2; 30 if(check(mid)){ 31 L=mid; 32 } 33 else{ 34 R=mid; 35 } 36 } 37 printf("%.3f\n",L); 38 return 0; 39 }