[bzoj3316]:JC loves Mkk

来自FallDream的博客,未经允许,请勿转载,谢谢。

n<=10^5

平均数最大的题目有一个经典的做法 就是二分答案 然后让所有数字减去那个答案 判断是否有大等于0的合法的一段即可

这道题显然可以开两个单调队列实现 然后二分的答案是实数,所以还要记一下是答案的区间。

复杂度nlogn

#include<iostream>
#include<cstdio>
#define MN 200000
#define INF 2000000000
#define ll long long
#define ld double
#define eps 1e-9
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

ll a[MN+5];int n,L,R,Ansl,Ansr;
struct MyQue
{
    int p[MN+5];ld s[MN+5];int top,tail;
    void clear(){top=0;tail=1;}
    void ins(int pos,ld y)
    {
        while(top>=tail&&y<s[top]) --top;
        p[++top]=pos;s[top]=y;
    }
    ld query(int pos)
    {
        while(top<tail&&p[tail]<pos) ++tail;
        if(top<tail) return INF+5;
        return s[tail];
    }
}Q,Q2;

bool check(ld c)
{
    Q.clear();Q2.clear();
    for(int i=L;i<=n;++i)
    {
        ld th=(ld)a[i]-c*i;
        if((i-L)&1)Q.ins(i-L,(ld)a[i-L]-c*(i-L));
        else Q2.ins(i-L,(ld)a[i-L]-c*(i-L));
        if(th>=((i&1)?Q.query(i-R):Q2.query(i-R))) return Ansl=((i&1)?Q.p[Q.tail]:Q2.p[Q2.tail]),Ansr=i,true;
    }
    return false;
}
inline ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
int main()
{
    n=read();L=read();R=read();
    for(int i=1;i<=n;++i) a[i]=a[i+n]=read();n<<=1;
    ld l=0,r=INF,mid;
    for(int i=1;i<=n;++i) a[i]+=a[i-1];
    for(int i=1;i<=100;++i)
    {
        mid=(l+r)/2.0;
        if(check(mid)) l=mid;
        else r=mid;
    }
    ll Ans=a[Ansr]-a[Ansl],F=Ansr-Ansl,g=gcd(Ans,F);
    Ans/=g;F/=g;
    if(F==1) printf("%lld",Ans);
    else printf("%lld/%lld\n",Ans,F);
    return 0;
}
posted @ 2017-05-15 19:14  FallDream  阅读(258)  评论(0编辑  收藏  举报