致中和,天地位焉,万物育焉。秋实大哥是一个追求中庸的人。
虽然秋实大哥的仰慕者众多,但秋实大哥不喜欢极端的妹纸。所以他想从所有仰慕自己的妹纸中挑选出一个符合中庸之道的。
每一个妹纸对秋实大哥的仰慕程度可以用一个整数 ai 来表示,秋实大哥想要找出这些数的中位数。
计算有限个数的数据的中位数的方法是:
把所有的同类数据按照大小的顺序排列。如果数据的个数是奇数,则中间那个数据就是这群数据的中位数; 如果数据的个数是偶数,则中间那2个数据的算术平均值就是这群数据的中位数。
Input
第一行有一个整数 n ,表示秋实大哥的仰慕者数目。
接下来 n 行,每行有一个正整数 ai 。
1≤n≤250000 , 1≤ai<231 。
Output
输出这 n 个数的中位数,保留一位小数。
Sample input and output
Sample Input | Sample Output |
---|---|
3 1 2 3 | 2.0 |
Hint
注意内存大小限制。
用小根堆实现。思想和用优先队列一样,但是优先队列会爆内存,所以手写堆。= =
如果将所有数排序,那么中位数一定在前一半多一个或者后一半多一个中,所以找中位数就只用用一半大小的数组存就好了。
读入一半多一个的数据后,之后每在堆中加一个数,再删掉堆中最小的。最后堆顶即为中位数。如果是偶数个,再加上下一层中小的取平均值即可。
#include <iostream>
#include <cstdio>
#define lid (fa << 1)
#define rid (fa << 1 | 1)
using namespace std;
unsigned int l[125005] = {0};
void push(unsigned int x)
{
l[0]++;
int fa = l[0];
l[fa] = x;
while(fa / 2 > 0){
if(l[fa / 2] > l[fa]){
int temp = l[fa];
l[fa] = l[fa / 2];
l[fa / 2] = temp;
fa = fa / 2;
}
else
break;
}
}
int down(int x)
{
int fa = x;
int temp;
int flag;
while(1){
if(rid > l[0] && lid <= l[0] && l[fa] > l[lid]){
temp = l[lid];
l[lid] = l[fa];
l[fa] = temp;
fa = lid;
if(fa == 2)
return 1;
}
else if(rid > l[0] && lid <= l[0]) break;
else if(rid <= l[0] && lid <= l[0]){
if(l[fa] <= l[lid] && l[fa] <= l[rid])
break;
else if(l[fa] > l[lid] && l[lid] <= l[rid]){
temp = l[lid];
l[lid] = l[fa];
l[fa] = temp;
fa = lid;
}
else if((l[fa] > l[rid] && l[rid] <= l[lid])){
temp = l[rid];
l[rid] = l[fa];
l[fa] = temp;
fa = rid;
}
}
else break;
}
return fa;
}
void pop()
{
int temp = l[l[0]];
l[l[0]] = l[1];
l[1] = temp;
l[0]--;
while(1){
int flag = down(1);
if(flag == 1)
break;
}
}
int main()
{
int n,t;
unsigned int x;
double out;
scanf("%d",&n);
t = n / 2 + 1;
for(int i = 0; i < t; i ++){
scanf("%u",&x);
push(x);
}
for(int i = t; i < n; i ++){
scanf("%u",&x);
push(x);
pop();
}
if(n % 2 == 1){
out = (double) l[1];
printf("%.1lf",out);
}
else{
if(n == 2)
out = (double) l[2] / 2;
else if(l[2] < l[3])
out = (double) l[2] / 2;
else
out = (double) l[3] / 2;
out += (double) l[1] / 2;
printf("%.1lf",out);
}
return 0;
}