ZOJ 3916|Buy Cakes|贪心|堆

你身上有 M 元,K张优惠券。商店共有 N 块蛋糕,使用一张优惠券可以买一块优惠价格的蛋糕。蛋糕i使用优惠券花费 bi ,不使用花费 ai 。问最多买多少块蛋糕。

开始方向想错跪跪跪。浪费了好多时间。
一直在想先 ai 买完再调整 bi 。。
然而正确姿势是先买完 bi 再调整 ai 。。
除了这点思路基本一样,但是就这点反了QwQ。
难怪一直觉得好像情况好复杂QwQ。
这个悲伤的故事告诉我们想不出来一定要更换方向QwQ。
好了不说伤心的事情了QwQ。
感觉GDOI要跪QwQ。
我又在说伤心的事情了QwQ。
祝zyr SHOI 2016第4轮Rank 1。(画风突变?)

首先按 bi 排序,选最小 k 个,如果已经超出M,那么这个就是最优方案了。
否则我们有两种选择:

  1. 不用优惠券买可以买的蛋糕,代价即为新蛋糕的原价
  2. 调整已经使用了优惠券的蛋糕,以新的优惠购买其他的蛋糕,代价即为旧蛋糕的优惠差和新蛋糕的优惠价

每步选择最优方案。
正确性显然。
时间复杂度 O(nlogn)

#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;++i)
typedef long long ll;
const int N = 100005;
struct Data { int a, b, c, i; } a[N], b[N];
bool cmpX(Data a, Data b) { return a.a < b.a; }
bool cmpY(Data a, Data b) { return a.b == b.b ? a.c > b.c : a.b < b.b; }
priority_queue<int, vector<int>, greater<int> > pq;
bool vis[N];
int main() {
    int t, n, k, i, pb, pa, ans; ll m;
    scanf("%d", &t);
    while (t--) {
        memset(vis, 0, sizeof vis);
        scanf("%d%d%lld", &n, &k, &m);
        FOR(i,1,n) {
            scanf("%d%d", &b[i].a, &b[i].b);
            b[i].c = b[i].a - b[i].b;
            b[i].i = i;
        }
        sort(b + 1, b + n + 1, cmpY);

        ans = 0; while (!pq.empty()) pq.pop();
        FOR(i,1,k)
            if (m >= b[i].b) {
                m -= b[i].b;
                ++ans;
                pq.push(b[i].c);
            } else break;
        FOR(i,k+1,n) a[i] = b[i];
        sort(a + k + 1, a + n + 1, cmpX);

        for (pa = pb = k + 1; pa <= n && pb <= n; ) {
            if (vis[a[pa].i]) { ++pa; continue; }
            if (vis[b[pb].i]) { ++pb; continue; }
            int k1 = a[pa].a, k2 = pq.empty() ? 2147483647 : pq.top() + b[pb].b;
            int mi = min(k2, k1);
            if (m < mi) break;
            m -= mi; ++ans;
            if (k1 < k2) vis[a[pa++].i] = 1;
            else {
                pq.pop();
                pq.push(b[pb].c);
                vis[b[pb++].i] = 1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

Buy Cakes

Description

Andy is always a hungry man. He never stopped eating something sweet, expecially cakes.
Yesterday his mother gave him some pocket money, and now, he has M dollars all together.
The cake shop provides N pieces of cakes, and each of them costs ai dollars respectively.
Fortunately, Andy has K discount coupons for that cake shop. When we use a coupon, we can buy a cake at a lower prize of bi dollars instead of the original ai dollars.
So, Andy wants you to help him find out how many cakes he can buy at most.

Input

There are multiple cases.
The first line contains the number of cases for this problem T ( 1T10 ).
For each case, the first line contains three integers N(1N105),K(0KN) , and M(0M1014) .
For next N lines, each line has two integers ai and bi ( 1biai109 ).

Output

For each case, output the number of cakes he can get at most.

Sample Input

2
4 1 7 
3 2 
2 2  
8 1  
4 3 
2 0 3
5 4
6 3

Sample Output

3
0
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值