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

来源:互联网 发布:c语言自定义结构体 编辑:程序博客网 时间:2024/05/16 05:33

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,保证问题有解,数据随机生成

题解:

首先二分答案

每个数减去二分的值,然后就只用判断是否存在一个子串的的和大于0

做一个前缀和,用单调队列维护前缀和递增以及元素个数即可.

因为要求长度必须是偶数所以对奇数位置和偶数位置各维护一个单调队列.

代码:

#include<iostream>#include<cstdio>#include<cstring>#define N 200010#define eps 1e-7using namespace std;long double s[N];int n,L,R,a[N],mx,S,q[2][N],l[2],r[2];int read(){  int x(0);char ch=getchar();  while (ch<'0'||ch>'9') ch=getchar();  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();  return x;}long long gcd(long long x,long long y){  if (!y) return x;  return gcd(y,x%y);} int check(long double x){  int k;  for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i]-x;  l[0]=l[1]=1;r[0]=r[1]=0;  for (int i=L;i<=n;i++){    k=i&1;    while (l[k]<=r[k]&&q[k][l[k]]<i-R) l[k]++;    while (l[k]<=r[k]&&s[i-L]<s[q[k][r[k]]]) r[k]--;    q[k][++r[k]]=i-L;    if (s[i]-s[q[k][l[k]]]>=0) return S=i-q[k][l[k]];  }   return 0;}int main(){  //freopen("a.in","r",stdin);  n=read();L=read();R=read();  for (int i=1;i<=n;i++) a[i]=read(),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=n*2;  long double l=0,r=mx;  while(r-l>eps){    long double mid=(l+r)/2.0;    if (check(mid)) l=mid;    else r=mid;  }  long double x=(l+r)/2.0;  long long G=(long long)(S*x+0.5);   long long temp=gcd(G,S);  G=G/temp;S=S/temp;  if (S==1) cout<<G<<endl;  else cout<<G<<"/"<<S<<endl;} 


0 0
原创粉丝点击