[USACO 2012 Feb Gold] Cow Coupons【贪心 堆】

传送门1:http://www.usaco.org/index.php?page=viewproblem2&cpid=118

传送门2:http://www.lydsy.com/JudgeOnline/problem.php?id=2590

 

又挂了一道贪心,好烦啊。

这一题应该要想到“撤回”操作就好办了。假设现在已经没有优惠券了,那么如果你想以优惠价格买下一头牛,就要撤回以前的用优惠券买的牛,具体就是加回p[i] - c[i]就行了,可以理解为花这么多钱买一张优惠券。然后就是维护3个小根堆了。

#include <cstdio>
#include <queue>

const int maxn = 50005;

int n, k, ans;
long long m, pp[maxn], cc[maxn];
bool book[maxn];
struct st1 {
	long long data;
	int id;
	bool operator<(const st1 & rhs) const {
		return data > rhs.data;
	}
};
std::priority_queue<st1> p, c;
struct st2 {
	long long data;
	bool operator<(const st2 & rhs) const {
		return data > rhs.data;
	}
};
std::priority_queue<st2> coupon;

int main(void) {
	freopen("coupons.in", "r", stdin);
	freopen("coupons.out", "w", stdout);
	scanf("%d%d%I64d", &n, &k, &m);
	while (k--) {
		coupon.push((st2){0});
	}
	for (int i = 1; i <= n; ++i) {
		scanf("%I64d%I64d", pp + i, cc + i);
		p.push((st1){pp[i], i});
		c.push((st1){cc[i], i});
	}
	
	while (m > 0 && ans < n) {
		while (book[p.top().id]) {
			p.pop();
		}
		while (book[c.top().id]) {
			c.pop();
		}
		if (p.top().data < c.top().data + coupon.top().data) {
			m -= p.top().data;
			if (m <= 0) {
				break;
			}
			book[p.top().id] = true;
			p.pop();
		}
		else {
			m -= (c.top().data + coupon.top().data);
			if (m <= 0) {
				break;
			}
			coupon.pop();
			coupon.push((st2){pp[c.top().id] - c.top().data});
			book[c.top().id] = true;
			c.pop();
		}
		++ans;
	}
	printf("%d\n", ans);
	return 0;
}

  

posted @ 2016-11-08 19:21  ciao_sora  阅读(406)  评论(0编辑  收藏  举报