zoukankan      html  css  js  c++  java
  • 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
    ",ansa,ansb);
    69     else
    70         printf("%lld
    ",ansa);
    71     return 0;
    72 }
    View Code
  • 相关阅读:
    ORACLE--Connect By、Level、Start With的使用(Hierarchical query-层次查询)
    小工具-ANT
    测试类。。。重写篇
    java代码----求最大值,平均值。。。
    java代码,输入n多个数,求其平均值,虽有重复,但是第二次,我就乱写了
    java代码求输入数的平均值~~~~
    java代码求输入的三个数的最大值
    java代码switch语句求分数等级
    java代码求分数等级的输出~~~
    java代码 求和1+1/2+1/3+1/4+1/5+1/6+.......+1/n 的值~~~~
  • 原文地址:https://www.cnblogs.com/liutianrui/p/7582467.html
Copyright © 2011-2022 走看看