51nod 平均数(马拉松14)

alpq654321 (命题人)
 
基准时间限制:4 秒 空间限制:131072 KB 分值: 80
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 3
1 2 3 4 5
Output示例
4.000

/*
51nod 平均数

题目:给你n个数,可以知道总共可以组成 (n+1)*n/2 个区间,那么请问这些区间中第k大的平均值
最开始是一点思路都没有,后来看到一个有点相似的题目,发现我们可以吧问题转换成 平均值大于
x的区间有多少个

这样就可以通过枚举答案,然后通过判断解决。用f[i]表示前i个数的和,那么:
Ave = (f[r]-f[l])/(r-l)    所以Ave >= x  --->  f[r]-rx >= f[l]-lx即前面出现的比当前值小的个数
但是发现 f[r]-rx 可以达到-10^10,而且是浮点型。于是又纠结了很久,一开始也想到了离散化(但总觉得会超时Orz)
结果发现的确是自己想太多,利用sort,每次查找当前值是第几个,然后利用树状数组维护即可。

hhh 2016/05/28 16:22:06
*/
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <cmath>
#include <algorithm>
#include <functional>
#include <map>
using namespace std;
#define lson  (i<<1)
#define rson  ((i<<1)|1)
typedef long long ll;
using namespace std;
const int maxn = 101010;
const double PI = 3.1415926;
const double eps = 1e-6;
double a[maxn];
ll s[maxn];
double f[maxn];
double g[maxn];
int n;
ll k;

void add(int x,int val)
{
    while(x <= 100000)
    {
        s[x] += val;
        x += (x&(-x));
    }
}

ll sum(int pos)
{
    ll ans = 0;
    while(pos > 0)
    {
        ans += s[pos];
        pos -= (pos&(-pos));
    }
    return ans;
}

bool cal(double x)
{
    memset(s,0,sizeof(s));
    f[0] = 0;
    for(int i = 1; i <= n; i++)
        f[i] = f[i-1] + a[i];
    ll num = 0;
    for(int i = 1; i <= n; i++)
    {
        f[i] -= (double)i*x;
        g[i] = f[i];
        if(f[i] > 0)
            num ++;
    }
    sort(g+1,g+n+1);

//    for(int i = 1;i <= n;i++)
//        cout << g[i] <<" ";
//    cout << endl;
    for(int i = 1; i <= n; i++)
    {
        int pla = lower_bound(g+1,g+n+1,f[i])-g;
        num += sum(pla);
        add(pla,1);
    }
    if(num >= k)
        return true;
    else
        return false;
}

int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&n);
    scanf("%lld",&k);
    double Max = 0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%lf",&a[i]);
        Max = max(a[i],Max);
    }
    double l = 0;
    double r = Max;
    while( r - l > eps)
    {
        double mid = (l+r)/2;
        if(cal(mid))
            l = mid;
        else
            r = mid-eps;
    }
    printf("%f\n",l);
    return 0;
}

  

posted @ 2016-05-31 22:54  Przz  阅读(200)  评论(0编辑  收藏  举报