题目链接: 点我跳转~
题意: 求中位数。
注意事项: (1)n最大为250000。 (2)内存限制大小为1500KB。
思路: 由于内存限制,只能开大概 n/2 大小的数组。如果 n 为偶数,排序之后,中位数的位置会出现在 n/2,和 n/2 + 1,
而如果 n 为奇数则中位数的位置在 n/2 + 1,所以数组大小开 n/2 + 1。首先对前 n/2 + 1个数字建立一个大根堆。对于之后的
输入维护这个大根堆。输入完成之后进行排序,根据 n 的奇偶来选择堆中最大,或第一第二大的数字求出中位数。
如果之前会堆排序的话,这道题就差不多可以AC了。
致中和,天地位焉,万物育焉。秋实大哥是一个追求中庸的人。
虽然秋实大哥的仰慕者众多,但秋实大哥不喜欢极端的妹纸。所以他想从所有仰慕自己的妹纸中挑选出一个符合中庸之道的。
每一个妹纸对秋实大哥的仰慕程度可以用一个整数 ai 来表示,秋实大哥想要找出这些数的中位数。
计算有限个数的数据的中位数的方法是:
把所有的同类数据按照大小的顺序排列。如果数据的个数是奇数,则中间那个数据就是这群数据的中位数; 如果数据的个数是偶数,则中间那2个数据的算术平均值就是这群数据的中位数。
Input
第一行有一个整数 n ,表示秋实大哥的仰慕者数目。
接下来 n 行,每行有一个正整数 ai 。
1≤n≤250000 ,1≤a i <2 ^31 。
Output
输出这n n 个数的中位数,保留一位小数。
Sample input and output
3 1 2 3
2.0
Hint
注意内存大小限制。
代码:
#include <stdio.h> #include <algorithm> #define N 125007 using namespace std; void downAdjust(int *num, int i, int n) //对i元素向下找到合适的位置 { int lchild, rchild; lchild = i * 2; rchild = i * 2 + 1; int max_i = i; if (i <= n/2) { if (num[lchild] > num[max_i] && lchild <= n) max_i = lchild; if (num[rchild] > num[max_i] && rchild <= n) max_i = rchild; if (max_i != i) { swap(num[i], num[max_i]); downAdjust(num, max_i, n); } } } void Build(int *num, int n) //建立一个大根堆 { for (int i = n/2; i >= 1; i--) downAdjust(num, i, n); } void Sort(int *num, int n) //堆排序 { Build(num, n); for (int i = n; i >= 1; i--) { swap(num[i], num[1]); downAdjust(num, 1, i - 1); } } int main() { int n, num[N]; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n/2 + 1; i++) { scanf("%d", &num[i]); } Build(num, n/2 + 1); int temp; for (int i = n/2 + 2; i <= n; i++) //对后一半的输入维护大根堆 { scanf("%d", &temp); if (temp >= num[1]) continue; num[1] = temp; downAdjust(num, 1, n/2 + 1); } Sort(num, n/2 + 1); if (n % 2) { printf("%.1lf\n", (double)num[n/2 + 1]); } else { double ans = num[n/2] >= num[n/2 - 1] ? num[n/2] : num[n/2 - 1]; ans += (double)num[n/2 + 1]; ans /= 2.0; printf("%.1lf\n", ans); } } return 0; }
时间: 2024-10-17 11:29:56