7-1 浦島太郎の玉手箱開き

题目内容

浦島太郎被海龟带到龙宫,过了三年吃香喝辣的舒适生活后,准备回家乡探(炫)亲(耀)。临走时,小龙女送给他一个漆黑的木箱子,说里面装有各种奇珍异宝。回到原先居住的渔村后,浦島太郎叫来全村的老少,吹嘘龙宫的宝贝如何如何好,要让大家开开眼界。但当他正准备打开箱子时,箱子中突然传出声音:”想要打开箱子的话必须先回答问题。问题很简单!我连续报N个数出来,每报一个数,你马上跟着说一个数,并且是我之前报的所有数值中的最大、最小和中位数的平均值。如果你回答错了或者回答慢了,箱子就会立刻消失。”浦島太郎被吓得直冒冷汗,但夸下的海口又不好意思收回,只好硬着头皮接受挑战。请你帮他完成任务。

注:把包含n(>0)个数值的序列按升序(非递减)排序后,如果n是偶数,则排在2/n​和2/n​+1位的两个数是中位数;如果n是奇数,排在2/n+1​位的是中位数。

输入格式

输入在第一行中给出整数N (1≤N≤4×10^5)。接下来一行给出N个非负整数,数值间用空格隔开,末尾的数值后面没有空格。所有数值不超过10^8。

输出格式

在一行中输出N个整数,第i个数值(1≤i≤N)表示输入的前i个整数中的最大值、最小值及中位数的平均值(整除)。数值间用空格分开,末尾的数值后面没有空格。

输入样例

5
3 2 1 4 5

输出样例

3 2 2 2 3

题目样例分析

{3},平均值: (3+3+3)/3 = 3
{3,2},平均值: (2+2+3+3)/4=2
{3,2,1},平均值: (1+2+3)/3=2
{3,2,1,4},平均值: (1+2+3+4)/4=2
{3,2,1,4,5},平均值: (1+3+5)/3=3

限制

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

栈限制

8192 KB

思路分析

由于题目数据规模大,使用平常的数组存储后排序,或者是每次进行插入排序都会导致时间超过限制。现提供如下思路:

最大值与最小值的求法:

直接使用max和min存储,每次输入即进行比较,比较后更改该值大小。

中位数求法:

建立两个优先级队列,分别是left和right。

left是最大堆,方便取最大元素,堆顶是中位数(轮次为偶数时,为中位数之一),其余元素是小于中位数的元素。

right是最小堆,方便取最小元素,堆顶在偶数轮是中位数之一,其余元素和奇数轮的堆顶是大于中位数的元素。

现每次插入数据,要维护如下规则:

left元素个数等于right元素个数,或,left元素比right元素多一个。

这样就可以很直接求出中位数。

要维护这样的规则,只需要分奇偶轮次,奇数轮保持增加left元素,偶数轮保持增加right元素即可。

具体来说,当想往left插入元素时,需判断是否小于right堆顶元素。如果是,则直接插入,如果不是,则应当插入right中,然后把right堆顶的元素放入left中,才能维护上面的规则。向right中插入同理。

代码实现

#include <bits/stdc++.h>
using namespace std;


const int N = 1e8 + 10;
const int M = -1e8 - 10;
int n, m, k, T;

signed main() {
	cin >> n;
	priority_queue<int> left;
	priority_queue<int, vector<int>, greater<int>> right;
	int max = M;
	int min = N;
	int lun = 0;
	while (n--) {
		lun++;
		int num, sum;
		scanf("%d", &num);
		if (num > max) {
			max = num;
		}
		if (num < min) {
			min = num;
		}
		if (left.empty() && right.empty()) {
			left.push(num);
		} else {
			if (left.size() > right.size()) {
				if (num >= left.top()) {
					right.push(num);
				} else {
					int temp = left.top();
					left.pop();
					left.push(num);
					right.push(temp);
				}
			} else {
				if (num <= right.top()) {
					left.push(num);
				} else {
					int temp = right.top();
					right.pop();
					right.push(num);
					left.push(temp);
				}
			}
		}


		//计算阶段
		if (lun != 1) {
			printf(" ");
		}
		if (lun % 2 == 1) {
			printf("%d", (min + max + left.top()) / 3);
		} else {
			printf("%d", (min + max + left.top() + right.top()) / 4);
		}
	}
	printf("\n");
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值