51Nod-1711-平均数

来源:互联网 发布:网络摄像头的安装步骤 编辑:程序博客网 时间:2024/06/05 20:13

ACM模版

描述

描述

题解

二分答案,数据结构用树状数组比较好,期间需要离散化一下下。这里给了 4s 时限,有些多了,应该是需要注意一下输入优化的。

这里我们先求一下前缀和 sum[] 和最大值 mx,然后二分,核心是 check(),需要用到树状数组 + 离散化。

至于树状数组用来处理什么呢?我们可以推出如下:
二分过程我们需要 check(m),所以需要求有 x 区间的平均数大于等于 m,而每一个区间 [i+1, j] 的平均数是 sum[j]  sum[i]j  i,所以呢,

sum[j]sum[i]mjmi
sum[j]mj(sum[i]mi)0
自然,我们需要考虑的实际上就是每个 sum[i]mi,但是这个值需要排序后进行离散化,接着就是对离散化后的这个序列进行树状数组处理,枚举右区间,查找符合要求的左区间数,然后逐个添加已经枚举过的右区间,作为左区间以备再次查找使用。

这个题简直就是为树状数组而设计的题,完美的利用了树状数组的功能。好题!

代码

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int MAXN = 1e5 + 5;const double ESP = 1e-5;struct note{    double val;    int pos;} a[MAXN];bool cmp(note a, note b){    return a.val < b.val;}inline int lowbit(int t){    return t & (-t);}int n;ll k;ll sum[MAXN];int dct[MAXN];int t[MAXN];void add(int x){    for (; x <= n; x += lowbit(x))    {        t[x]++;    }}ll find(int x){    ll ans = 0;    for (; x; x -= lowbit(x))    {        ans += t[x];    }    return ans;}bool check(double m){    a[0].val = a[0].pos = 0;    for (int i = 1; i <= n; i++)    {        a[i].val = sum[i] - m * i;        a[i].pos = i;    }    sort(a, a + n + 1, cmp);    int cnt = 0;    ll x = 0;    //  discretize    for (int i = 0; i <= n; i++)    {        if (!i || a[i].val != a[i - 1].val)        {            cnt++;        }        dct[a[i].pos] = cnt;    }    memset(t, 0, sizeof(t));    add(dct[0]);    for (int i = 1; i <= n; i++)    {        x += find(dct[i]);        add(dct[i]);    }    if (x >= k)    {        return 1;    }    return 0;}template <class T>inline void scan_d(T &ret){    char c;    ret = 0;    while ((c = getchar()) < '0' || c > '9');    while (c >= '0' && c <= '9')    {        ret = ret * 10 + (c - '0'), c = getchar();    }}int main(){    scan_d(n), scan_d(k);    ll mx = 0;    for (int i = 1; i <= n; i++)    {        scan_d(sum[i]);        mx = max(mx, sum[i]);        sum[i] += sum[i - 1];    }    double l = 0, r = mx, m;    while (r - l > ESP)    {        m = (l + r) / 2;        if (check(m))        {            l = m;        }        else        {            r = m;        }    }    printf("%lf\n", l);    return 0;}
原创粉丝点击