UVA11136 Hoax or what

知识点:堆

这个题的题意比较好理解,但是比较容易写错,至少我是这么感觉的,看到题,可以很自然的想到用两个堆,一个大根堆一个小根堆来维护数据,但是这个不是对顶堆,然后每一天的最后,我们从分别拿出来一个数,统计答案就行了,题目保证每天的最后都至少有两张,这个想法很自然,但是这个样子是可能出错的,想象一下,假如实际剩余的消费券已经不多了,但是你用完的消费券已经很多了,然后来了一张很小的消费券,那么它进入大根堆的话就会被放的很靠后,前面有很多实际已经用完的但是还没有被你出堆的消费券,然后那些消费券都像是被向前推了一下似的,就有可能会有一个实际已经被用过的再被使用,这样就错了,出错的地方就在于有些用完的消费券不能留着了,又看了看数据,每个消费券的数据范围正好可以来散列,那么就是这个样子了,我们开一数组来散列记录每种消费券的数目,每天结束的时候,循环遍历,数目为零的券都直接删除,直到找到第一个数目不为零的券,用来统计答案,两个堆都是这个样子,这样就不会出错了,

这个题用堆写容易出错的地方就是没有及时删除堆里面实际数量已经是0的消费券,所以每次从堆里面找消费券的时候都要找第一个数量不为0的消费券,并且前面的都要删除

还是感慨一下,一开始看见这个题就有点轻敌了,以为很简单,最后是看了别人的题解才过的,希望自己以后不要这么轻敌了

本题还有更简单的multiset的写法,就不写了

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;

int h[N];

int main() {
	int n;
	while (cin >> n && n) {
		memset(h, 0, sizeof(h));
		priority_queue<int> q1;
		priority_queue<int, vector<int>, greater<int>> q2;
		long long ans = 0;
		while (n--) {
			int k;
			scanf("%d", &k);
			while (k--) {
				int x;
				scanf("%d", &x);
				q1.push(x); q2.push(x);
				h[x]++;
			}
			while (!h[q1.top()]) q1.pop();
			while (!h[q2.top()]) q2.pop();
			ans += (long long) q1.top() - q2.top();
			h[q1.top()]--; h[q2.top()]--;
		}
		cout << ans << '\n';
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值