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
  • 相关阅读:
    利用burpsuite实现重放攻击
    木马分析(隐藏分析)实验
    使用wireshark分析TLS
    ECharts折线图循环展示数据、自定义色值(渐变)
    Sumblime Text3格式化代码
    ECharts柱状图彩色柱状图(渐变),自定义鼠标移入小圈颜色、鼠标移入后提示框显示不全问题、渲染到页面中
    C#多线程学习(五) 多线程的自动管理(定时器)
    SQL取出 所有周六 周日的日期
    C#多线程学习(二) 如何操纵一个线程
    简单读写XML文件
  • 原文地址:https://www.cnblogs.com/liutianrui/p/7582467.html
Copyright © 2011-2022 走看看