首页 > 代码库 > BZOJ 3316 JC loves Mkk 二分答案+单调队列
BZOJ 3316 JC loves Mkk 二分答案+单调队列
题目大意:给定一个环,要求在这个环上截取长度为偶数且在[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-7 using 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; else r=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; else cout<<numerator<<'/'<<denominator<<endl; return 0; }
BZOJ 3316 JC loves Mkk 二分答案+单调队列
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。