您的位置:首页 > 其它

【bzoj3316】JC loves Mkk 二分答案+单调队列

2018-01-01 20:15 337 查看
Description



Input

第1行,包含三个整数。n,L,R。

第2行n个数,代表a[1..n]。

Output

仅1行,表示询问答案。

如果答案是整数,就输出整数;否则,输出既约分数“P/Q”来表示。

Sample Input

5 3 4

3 1 2 4 5

Sample Output

7/2

HINT

1≤L≤R≤n≤10^5,0≤ai≤10^9,保证问题有解,数据随机生成

题解

二分答案+单调队列

二分平均值,每个数减去平均值,如果存在一段L-R长度的区间和大于0,则存在比当前平均值更大的平均值。

对于i,我们维护i-R~i-L区间前缀和的最小值,显然单调队列。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 1000000000
#define mod 65537
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;
}
const long double eps=0.00000001;
const int N=200005;
int n,m,L,R,q[2]
,Head[2],tail[2],a
;
ll A,B; long double sum
,l=0,r=0;
ll gcd(ll a,ll b){return (b)?gcd(b,a%b):a;}
bool judge(long double mid)
{
for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]-mid;
Head[0]=Head[1]=1;tail[0]=tail[1]=0;
for (int i=L;i<=n;i++)
{
int j=i-L,k=i&1;
while (Head[k]<=tail[k]&&sum[q[k][tail[k]]]>sum[j]) tail[k]--;
q[k][++tail[k]]=j;if (i-q[k][Head[k]]>R) Head[k]++;
if (sum[i]-sum[q[k][Head[k]]]>0)
{
B=i-q[k][Head[k]];return 1;
}
}
return 0;
}
int main()
{
n=read();L=read();R=read();L+=L&1;R-=R&1;
for (int i=1;i<=n;i++)
{
a[i]=a[i+n]=read();if (a[i]>r) r=a[i];
}
n<<=1;
while (l+eps<r)
{
long double mid=(l+r)/2;
if (judge(mid)) l=mid;else r=mid;
}
long double ans=(l+r)/2; A=(ll)(ans*B+0.5);
ll tmp=gcd(A,B); A/=tmp; B/=tmp;
if (B==1) printf("%lld\n",A); else printf("%lld/%lld\n",A,B);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: