1. 程式人生 > >【bzoj3316】JC loves Mkk 二分答案+單調佇列

【bzoj3316】JC loves Mkk 二分答案+單調佇列

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][N],Head[2],tail[2],a[N]; ll A,B; long double sum[N],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); }