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

来源:互联网 发布:java写的毕业设计 编辑:程序博客网 时间:2024/05/21 06:40

…平均数最大我居然不知道要二分答案,似乎是很常见的思路?我好弱。

每次二分一个答案mid,维护aimid的前缀和,每次枚举一个i,将sumiL加入单调队列,并保证队列中的点都在iR..iL之内,每次要找区间的最小值mn,看看sumimn0是否成立,维护最小值可以单调队列来解决。

#include<iostream>#include<cstdio>#define eps 1e-7#define N 200005using namespace std;long double sum[N];int a[N];int n,L,R,mx;int Q[2][N],l[2],r[2];long long ans;inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}long long gcd(long long a,long long b){    return b==0?a:gcd(b,a%b);}bool judge(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;        int *q=Q[w];        while (r[w]>=l[w]&&sum[x]<sum[q[r[w]]]) r[w]--;        while (r[w]>=l[w]&&q[l[w]]<i-R) l[w]++;        q[++r[w]]=x;        if (sum[i]-sum[q[l[w]]]>=0) return ans=i-q[l[w]];    }    return false;}int main(){    n=read(); L=read(); R=read();    if (L&1) L++;    if (R&1) R--;    for (int i=1;i<=n;i++)    {        a[i]=read();        mx=max(a[i],mx);        a[i+n]=a[i];    }    n<<=1;    long double l=0,r=mx;    while (r-l>=eps)    {        long double mid=(l+r)/2;        if (judge(mid)) l=mid;        else r=mid;    }    long double x=(l+r)/2;    long long w=(long long)(ans*x+0.5);    long long d=gcd(w,ans);    w/=d; ans/=d;    if (ans==1) cout << w;    else cout << w << "/" << ans;    return 0;}
1 0