bzoj3316 JC loves Mkk题解

Posted Hzoi_joker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3316 JC loves Mkk题解相关的知识,希望对你有一定的参考价值。

3316: JC loves Mkk

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 979  Solved: 316
[Submit][Status][Discuss]

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,保证问题有解,数据随机生成
  这道题其实挺有意思的,既约分数这一点恐怕卡住了无数想打二分的像我一样的蒟蒻,然而,如果我们观察到问题的本质我们就可以抛开既约分数对于二分答案的限制。
  所以,为了方便,我们先假设这道题只是让我们输出小数,那么假设我们二分出来的答案是x,l为我们选择的左边界则:
    sum[i]-sum[l-1]/(i-l+1)>=x   (L<=i-l+1<=R (i-l+1)%2==0)
  将式子化简可得sum[i]-i*x>=sum[l-1]-(l-1)*x那么每一个点所提供的信息在二分答案确定后也就可以确定了。值得注意的是由于题目偶数的限制,我们需要准备两个单调队列去满足这一条件,利用滚动数组即可,同时,我们也应注意到,我们实际要求的是sum[l-1]-(l-1)*x最小,对于l自己本身并无要求,所以我们单调队列存的实际是l-1的信息。
  现在,除了既分约数基本这道题解决完了。我们可以注意到,对于每次check二分的值成功时他所对应的答案一定是递增的,所以我们完全可以抛开我们二分的值,直接现求当前答案,这样就可以很好的解决既分约数对于二分答案的限制了。
  
技术分享
 1 #pragma GCC optimze("O3")
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<queue>
 7 #include<algorithm>
 8 #include<cmath>
 9 #include<map>
10 #include<vector>
11 #define N 100005
12 using namespace std;
13 int n,L,R;
14 long long a[2*N],sum[N*2],mx;
15 int q[2][N*2];
16 int hea[2],en[2];
17 long long ansa,ansb;
18 long long gcd(long long x,long long y)
19 {
20     if(y==0)return x;
21     return gcd(y,x%y);
22 }
23 bool check(double x)
24 {
25     memset(q,0,sizeof(q));
26     hea[0]=hea[1]=1,en[0]=en[1]=0;
27     int now=1,la=0;
28     for(int i=L;i<2*n;i++)
29     {
30         swap(now,la);
31         while(hea[now]<=en[now]&&sum[q[now][en[now]]]-(double)(q[now][en[now]])*x>sum[i-L]-(double)(i-L)*x) en[now]--;
32         en[now]++;
33         q[now][en[now]]=i-L;
34         if(i>R)
35             while(hea[now]<=en[now]&&q[now][en[now]]<i-R)hea[now]++;
36         if(sum[i]-sum[q[now][hea[now]]]>=(double)(i)*x-(double)(q[now][hea[now]])*x)
37         {
38             ansa=sum[i]-sum[q[now][hea[now]]];
39             ansb=i-q[now][hea[now]];
40             long long t=gcd(ansa,ansb);
41             ansa/=t;
42             ansb/=t;
43             return 1;
44         }
45     }
46     return 0;
47 }
48 int main()
49 {
50     scanf("%d%d%d",&n,&L,&R);
51     if(L%2)L++; if(R%2)R--;
52     for(int i=1;i<=n;i++)
53     {
54         scanf("%lld",&a[i]);
55         a[i+n]=a[i];
56         mx=max(mx,a[i]);
57     }
58     for(int i=1;i<n*2;i++)
59         sum[i]+=sum[i-1]+a[i];
60     double li=0,ri=mx;
61     while(ri-li>1e-6)
62     {
63         double mid=(li+ri)/2;     
64         if(check(mid)) li=mid;
65         else ri=mid;
66     }
67     if(ansb!=1)
68         printf("%lld/%lld\n",ansa,ansb);
69     else
70         printf("%lld\n",ansa);
71     return 0;
72 }
View Code












以上是关于bzoj3316 JC loves Mkk题解的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3316JC loves Mkk 分数规划+单调队列

bzoj3316: JC loves Mkk

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

[BZOJ3569]DZY Loves Chinese II(随机化+线性基)

BZOJ3563/3569DZY Loves Chinese II 线性基神题

●BZOJ 3640 JC的小苹果