题解:Luogu_P3045 [USACO12FEB] Cow Coupons G

题解:Luogu_P3045 [USACO12FEB] Cow Coupons G

Luogu_P3045 [USACO12FEB] Cow Coupons G
贪心

Solution

首先有个最初的的想法,将所有牛不用优惠券的价格扔进一个小根堆里,用优惠券的价格扔进一个小根堆,每次比较两个堆顶的价格,选花钱最少的。

看组数据:

3 2 6
5 1
3 1
4 2

按照我们的策略,会选 1、2 号牛,实际如果选 1、3 号牛使用优惠券,剩下的钱可以买下 2 号牛。

问题出在哪里?我们没能正确分配对哪头牛使用优惠券,不过好在这种贪心方法虽然不能保证买到的牛最多,但能保证选到的牛最后都会被买到。(自己讨论一下哪些情况会被选到,发现扔掉都是不优的)

本质的问题出在我们在分配优惠券时,没能考虑每张优惠券能省多少,导致有些优惠券省的钱太少了,买同样的牛,将一些优惠券分配给 \(p_i-c_i\) 更大的牛总价钱会更少。

于是我们再弄一个小根堆,用来存 \(k\) 张优惠券的省钱情况,如果有牛可以更省就把优惠券给新的牛用。

Code

计算细节看代码

//P3045

#include <iostream>
#include <cstdio>
#include <map>
#include <queue>

#define lld long long
#define pii pair <int, int>

using namespace std;

inline lld read()
{
    lld val = 0;
    bool si = 0;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        si ^= ch == '-';
    for (;  isdigit(ch); ch = getchar())
        val = (val << 3) + (val << 1) + (ch ^ 48);
    return si ? - val : val;
}

const int N = 50005;

int n, k, p[N], c[N], ans;
lld m;
bool vis[N];

priority_queue <pii, vector <pii>, greater <pii> > heap, heac;
priority_queue <int, vector <int>, greater <int> > cost;

int main()
{
    n = read(), k = read(), m = read();
    for (int i = 1; i <= n; i ++)
    {
        heap.push(make_pair(p[i] = read(), i));
        heac.push(make_pair(c[i] = read(), i));
    }
    for (int i = 1; i <= k; i ++)
        cost.push(0);
    
    while (!heap.empty() && !heac.empty())
    {
        pii nowp = heap.top();
        if (vis[nowp.second])
        {
            heap.pop();
            continue;
        }
        pii nowc = heac.top();
        if (vis[nowc.second])
        {
            heac.pop();
            continue;
        }

        if (nowp.first <= nowc.first + cost.top())
        {
            m -= nowp.first;
            vis[nowp.second] = 1;
            heap.pop();
        }
        else
        {
            m -= nowc.first + cost.top();
            vis[nowc.second] = 1;
            heac.pop();
            cost.pop();
            cost.push(p[nowc.second] - c[nowc.second]);
        }

        if (m < 0) break;

        ans ++;
    }

    printf("%d\n", ans);

    return 0;
}
posted @ 2025-02-07 08:26  nueryim  阅读(39)  评论(0)    收藏  举报