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
先二分答案,将n个数中的最大值作为二分的上边界
设二分的答案为t,
我们可以新建一个数组f表示所有前i个数(ai-t)的和,则f[i]<0表示1~i这个区间的平均数小于t。
则f[i]==0表示1~i这个区间的中位数等于t。
则f[i]>0表示1~i这个区间的中位数等于t。
再确立这样一个事实,假设
一个区间1~x有x个元素,其中和是sum1。
另一个区间1~y(假设x<y),有y个元素,其中和为sum2.若sum2<sum1,则区间x~y的sum<0,既区间x~y的平均数小于t。
接下来下面这个f(i)
f(i) | 1 | 2 | 3 | 4 | 5 | 6 |
sum | -1 | 2 | 0 | 5 | 1 | -3 |
逆序数嘛,树状数组随便搞下就好,不过这题的f(i)可能会超LL,,要离散化一下
下面上代码“
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <string.h>
#include<math.h>
using namespace std;
typedef long long LL;
#define N 100000
#define exp 1e-6
LL n,k;
int tree[N+10];
double sz[N+10];
struct Node {
double val;
int pos;
} f[N+10];
bool cmp(Node a,Node b) {
return a.val<b.val;
}
int lowbit(int x) {
return x&-x;
}
void add(int x,int v) {
while(x<=n) {
tree[x]+=v;
x+=lowbit(x);
}
}
int Sum(int x) {
int tot=0;
while(x) {
tot+=tree[x];
x-=lowbit(x);
}
return tot;
}
bool solve(double t) {
memset(tree,0,sizeof(tree));
f[1].val=sz[1]-t;
f[1].pos=1;
for(int i=2; i<=n; i++) {
f[i].val=f[i-1].val+sz[i]-t;
f[i].pos=i;//离散化
}
sort(f+1,f+n+1,cmp);
LL sum=0;
for(int i=1; i<=n; i++) {
if(f[i].val>=0)sum++;//这里要注意,,wa了好久。。
sum+=Sum(f[i].pos);
add(f[i].pos,1);
}
if(sum>=k) return 1;
else return 0;
}
int main() {
//freopen("input.txt","r",stdin);
scanf("%I64d%I64d",&n,&k);
double r;
for(int i=1; i<=n; i++) {
scanf("%lf",&sz[i]) ;
r=max(r,sz[i]);
}
double mid,l=0;
while(r-l>exp) {
mid=((r+l)/2);
if(solve(mid))l=mid;
else r=mid;
}//二分
printf("%.3f\n",r);
return 0;
}