您的位置:首页 > 其它

日常训练 平均数

2017-01-10 18:39 316 查看
题意简述:长度为n的序列,列出所有子串,求第k小的平均值。n≤100000

首先二分答案ave,将每个数都减去ave,平均数小于ave的区间在新的数列里平均数小于0,也就是区间和小于0。将区间做一遍前缀和,每有一对逆序对(包括0号位),就有一个小于0的区间,求逆序对归并树状数组都可。

#include<bits/stdc++.h>
#define ll long long
#define MAXN 100050
using namespace std;
struct rec{
double s;
int num;
};
rec c[MAXN];
int tr[MAXN],a[MAXN],n,k;
bool cmp(rec a,rec b){
return a.s > b.s;
}
int query(int x){
if (x == 0) return 0;
return tr[x] + query(x - (x & -x));
}
void modify(int x){
if (x > n + 1) return;
tr[x]++;
modify(x + (x & -x));
}
ll check(double ave){
c[0].s=0;
for (int i = 1;i <= n;i++)
c[i].s = c[i - 1].s + a[i] - ave;
for (int i = 0;i <= n;i++)
c[i].num = i;
sort(c,c + n + 1,cmp);
memset(tr,0,sizeof(tr));
ll cnt=0;
for (int i = 0;i <= n;i++){
cnt += query(c[i].num + 1);
modify(c[i].num + 1);
}
return cnt;
}
int main(){
freopen("ave.in","r",stdin);
freopen("ave.out","w",stdout);
scanf("%d%d",&n,&k);
for (int i=1;i <= n;i++)
scanf("%d",&a[i]);
double l,r,mid;
l=0;r=1e9;
while (l+1e-5<r){
mid=(l+r)/2;
if (check(mid)>=k)
r=mid;
else
l=mid;
}
printf("%.4lf\n",l);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分