洛谷P3045 [USACO12FEB] Cow Coupons G(堆,反悔贪心)

题目链接

https://www.luogu.com.cn/problem/P3045

思路

我们先贪心地使用 k k k个最小的优惠假,再考虑如何反悔。

假设 s u m sum sum表示现在用了多少钱, i i i表示一个已经使用了优惠卷的物品, j j j表示一个未购买的物品。

如果用原价购买 j j j,则需要用: s u m + p j sum + p_{j} sum+pj

如果用优惠假购买 j j j,则需要用: s u m − c i + p i + c j sum - c_{i} + p_{i} + c_{j} sumci+pi+cj

如果要换成用原价购买 i i i,用优惠价购买 j j j,则需要满足: s u m − c i + p i + c j < s u m + p j sum - c_{i} + p_{i} + c_{j} < sum + p_{j} sumci+pi+cj<sum+pj,化简得到: p i − c i < p j − c j p_{i}-c_{i} < p_{j}-c_{j} pici<pjcj。换句话说,就是物品 i i i用优惠卷节省的钱要 < < <物品 j j j用优惠卷节省的钱。

这里,每一个物品用优惠卷节省的钱可以使用优先队列 d e l t a delta delta来维护。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e4 + 5;
int n, k, m;
int p[N], c[N];
bool st[N];
priority_queue < pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>>P, C;
priority_queue<int, vector<int>, greater<int>>delta;
void solve()
{
	cin >> n >> k >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> p[i] >> c[i];
		P.push({p[i], i});
		C.push({c[i], i});
	}
	//初始化k个,保证后面delta里面一定有k个值
	for (int i = 1; i <= k; i++) delta.push(0);

	int ans = 0;
	while (P.size())
	{
		pair<int, int> px = P.top();
		pair<int, int> cx = C.top();
		//买过的就不考虑了
		if (st[px.second])
		{
			P.pop();
			continue;
		}
		if (st[cx.second])
		{
			C.pop();
			continue;
		}

		//使用优惠卷的价格:delta.top() + cx.first
		//原价:px.first
		if (delta.top() + cx.first > px.first)
		{
			m -= px.first;
			P.pop();
			st[px.second] = true;
		}
		else
		{
			m -= (cx.first + delta.top());
			delta.pop();
			C.pop();
			st[cx.second] = true;
			delta.push({p[cx.second] - c[cx.second]});
		}
		if (m >= 0) ans++;
		else break;
	}
	cout << ans << endl;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int test = 1;
	// cin >> test;
	for (int i = 1; i <= test; i++)
	{
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值