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
思路:
假设求平均值大于等于x的区间,则(sum[r] - sum[l - 1] ) / (r - l + 1) >= x;
即:sum[r] - x*r >= sum[l - 1] - x*(l - 1);(条件)
建立一个数组,每个成员的值为sum[i] - x*i,计算这个数组中满足条件的数量即可,计算时用到树形数组计算逆序对的思想。
#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
const double EPS = 1e-6;
int tree[MAXN];
int kase, n, a[MAXN];
ll k, sum[MAXN];
double b[MAXN],h[MAXN];
int lowbit(int x)
{
return x & (-x);
}
ll getSum(int x)
{
ll result = 0;
while (x > 0)
{
result += tree[x];
x -= lowbit(x);
}
return result;
}
void add(int x,int val)
{
while (x <= n+1)
{
tree[x] += val;
x += lowbit(x);
}
}
ll check(double k)
{
memset(tree, 0, sizeof(tree));
for (int i = 0; i <= n; ++i)
{
b[i] = h[i] = sum[i] - (i * k);
}
sort(h, h + n + 1);
int d = unique(h, h + n + 1) - h;
ll result = 0;
for (int i = 0; i <= n; ++i)
{
int x = lower_bound(h, h + d, b[i]) - h + 1;
result += getSum(x);
add(x, 1);
}
return result;
}
double find(ll k)
{
double left = 1, right = 100000;
while (right - left >= EPS)
{
double mid = (left + right)/2.0;
if (check(mid) < k)
{
right = mid;
}
else
{
left = mid;
}
}
return (left + right)/2.0;
}
int main()
{
cin >> n >> k;
sum[0] = 0;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
sum[i] = sum[i-1] + (double)a[i];
}
double result = find(k);
cout << setprecision(10) << result << endl;
return 0;
}