[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; }