zoukankan      html  css  js  c++  java
  • 51nod1711 平均数

    Description

    LYK有一个长度为n的序列a。
    他最近在研究平均数。
    他甚至想知道所有区间的平均数,但是区间数目实在太多了。
    为了方便起见,你只要告诉他所有区间(n*(n+1)/2个区间)中第k大的平均数就行了。

    Input

    第一行两个数n,k(1<=n<=100000,1<=k<=n*(n+1)/2)。接下来一行n个数表示LYK的区间(1<=ai<=100000)。

    Output

    一行表示第k大的平均数,误差不超过1e-4就算正确。

    Input示例

    5 31 2 3 4 5

    Output示例

    4.000

    思路

    首先看题目求区间第k大,首先想到分第k大的平均数x。问题转化为如何快速求任意区间的平均数大于x的个数,先求求前缀和,则可以表示为(sum[r] - sum[l-1])/(r - l +1) > x 的区间个数,转化一下即为sum[r] - r*x > sum[l-1] - (l-1) * x;即形成一个新的数组sum[i]- i * x,求满足条件的区间有多少个,离散化一下,用树状数组统计一下就行。
    注意:i从0开始,sum[0] = 0;也要算进去,不然会把0-1的区间漏掉。

    Code

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define MAXN 100010
     5 typedef long long ll;
     6 using namespace std;
     7 ll sum[MAXN];
     8 double a[MAXN],b[MAXN];
     9 int tree[MAXN];
    10 int n;
    11 ll k;
    12 
    13 int lowbit( int x)
    14 {
    15     return x & -x;
    16 }
    17 void add(int k)
    18 {
    19     while(k <= n + 1)
    20     {
    21         tree[k] ++;
    22         k += lowbit(k);
    23     }
    24 }
    25 int Sum(int k)
    26 {
    27     int sum = 0;
    28     while(k)
    29     {
    30         sum += tree[k];
    31         k -= lowbit(k);
    32     }
    33     return sum;
    34 }
    35 long long check(double x)
    36 {
    37     memset(tree, 0, sizeof(tree));
    38     for(int i = 0; i <= n; i++)
    39         a[i] = b[i] = sum[i] - i * x;
    40     sort(a, a + 1 + n);
    41     int num = unique(a, a + 1 + n) - a;
    42     long long ans = 0;
    43     for(int i = 0; i <= n; i++)
    44     {
    45         int temp = lower_bound(a, a + num, b[i]) - a + 1;
    46         ans += Sum(temp);
    47         add(temp);
    48     }
    49     return ans;
    50 }
    51 int main()
    52 {
    53     scanf("%d%I64d",&n,&k);
    54     int temp;
    55     sum[0] = 0;
    56     for(int i =  1; i <= n; i++)
    57     {
    58         scanf("%d",&temp);
    59         sum[i] = sum[i - 1] + temp;
    60     }
    61     double l = 1.0, r = 100000.0;
    62     while(r - l >= 1e-6)
    63     {
    64         double mid = (l + r) / 2.0;
    65         if (check(mid) >= k)
    66             l = mid;
    67         else
    68             r = mid;
    69     }
    70     printf("%.4f
    ",(r + l)/2.0);
    71     return 0;
    72 }
  • 相关阅读:
    linux grep命令
    PHP 利用simplexml_load_file 读取XML对应的字段 然后存入mysql数据库
    php 设计模式之单类模式
    Mac C#开发工具Rider安利与环境配置教程
    模拟,贪心,枚举(二)
    模拟,贪心,枚举
    10.10 review
    review 10.9
    10.6 review
    9.28 review
  • 原文地址:https://www.cnblogs.com/yutingmoran/p/5901463.html
Copyright © 2011-2022 走看看