BZOJ 3316 JC loves Mkk 二分答案+单调队列

来源:互联网 发布:打印机无法网络打印 编辑:程序博客网 时间:2024/06/05 09:32

题目大意:给定一个环,要求在这个环上截取长度为偶数且在[L,R]区间内的一段,要求平均值最大

看到环果断倍增

看到平均值最大果断二分答案

看到长度[L,R]果断单调队列

对数组维护一个前缀和,对前缀和维护单调递增的单调队列

每扫过一个数sum[i],将sum[i-L]加入单调队列,再把距离i超过R的点删掉

长度为偶数?对奇数位置和偶数位置分别维护一个单调队列即可

每次找到大于0的子串之后记录一下分母再退出就行了

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 100100#define EPS 1e-7using namespace std;int n,L,R,max_num,a[M<<1];long double sum[M<<1];long long numerator,denominator;int q[2][M],r[2],h[2];bool Judge(long double x){int i;for(i=1;i<=n;i++)sum[i]=sum[i-1]+(a[i]-x);r[0]=r[1]=h[0]=h[1]=0;for(i=L;i<=n;i++){int *q=::q[i&1],&r=::r[i&1],&h=::h[i&1],x=i-L;while( r-h>=1 && sum[q[r]]>sum[x] )q[r--]=0;q[++r]=x;while( i-q[h+1]>R )q[++h]=0;if(sum[i]-sum[q[h+1]]>=0)return denominator=i-q[h+1];}return false;}long double Bisecion(){long double l=0,r=max_num;while(r-l>EPS){long double mid=(l+r)/2;if( Judge(mid) )l=mid;elser=mid;}return (l+r)/2;}int main(){int i;cin>>n>>L>>R;if(L&1) L++;if(R&1) R--;for(i=1;i<=n;i++){scanf("%d",&a[i]);max_num=max(max_num,a[i]);a[i+n]=a[i];}n<<=1;long double ans=Bisecion();numerator=(long long)(ans*denominator+0.5);long long gcd=__gcd(numerator,denominator);numerator/=gcd;denominator/=gcd;if(denominator==1)cout<<numerator<<endl;elsecout<<numerator<<'/'<<denominator<<endl;return 0;}


0 0
原创粉丝点击