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

PoPoQQQ大爷:

看到平均值最大果断二分答案
看到长度[L,R]果断单调队列

维护一个前缀和的单调递增队列,枚举到i把i-L进队i-R之前的出队
然后长度为偶数分开维护两个单调队列即可
似乎此题犯了我好多sb错误 ,各种不同姿势的tle
二分答案一定要用long double
二分答案一定要用long double
二分答案一定要用long double
重要的事说三遍!!

#include<set>
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define T 220006
#define MX 1e9
#define pa pair<int,int>
using namespace std;
long double sum[T];
int a[T];
int n,L,R,mx;
int q[2][T],l[2],r[2];
long long ans;
int sc()
{
    int i=0,f=1; char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
    return i*f;
}
long long gcd(long long x,long long y){return x==0?y:gcd(y%x,x);}
bool jud(long double y)
{
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]-y;
    l[0]=l[1]=1; r[0]=r[1]=0;
    for(int i=L;i<=n;i++)
    {
        int w=i&1,x=i-L;
        while(r[w]>=l[w]&&sum[x]<sum[q[w][r[w]]])r[w]--;
        while(r[w]>=l[w]&&q[w][l[w]]<i-R)l[w]++;
        q[w][++r[w]]=x;
        if(sum[i]-sum[q[w][l[w]]]>=0) return ans=i-q[w][l[w]];
    }
    return 0;
}
int main()
{
    n=sc(),L=sc(),R=sc();
    for(int i=1;i<=n;i++)a[i]=sc(),mx=max(mx,a[i]);
    for(int i=1;i<=n;i++)a[i+n]=a[i];
    if(L&1)L++;if(R&1)R--;n*=2;
    long double l=0,r=mx;
    while(r-l>1e-7)
    {
        long double mid=(l+r)/2;
        if(jud(mid))l=mid;
        else r=mid;
    }
    long double x=(l+r)/2;
    long long w=(long long)(ans*x+0.5);
    long long Gcd=gcd(w,ans); 
    w/=Gcd;ans/=Gcd;
    if(ans==1)cout<<w;  else cout<<w<<"/"<<ans;
    return 0;
}

你可能感兴趣的:(单调队列,二分答案)