Loading

P3045

题目描述

市场上有 \(N\) 头奶牛,第 \(i\) 头奶牛价格为 \(P_i\)。FJ 有 \(K\) 张优惠券,使用优惠券购买第 \(i\) 头奶牛时价格会降为 \(C_i\),每头奶牛只能使用一次优惠券。求花不超过 \(M\) 元最多可以买多少奶牛。

数据范围

  • \(1 \le K \le N \le 5 \times 10^4\)
  • \(1 \le C_i \le P_i \le 10^9\)
  • \(1 \le M \le 10^{14}\)

题解

反悔贪心。

我们讨论 \(M\) 元不足以买下所有奶牛的情况。

首先考虑一个朴素的贪心。使用优惠劵肯定优于不使用优惠劵,贪心地取 \(C\) 最小的奶牛用完 \(K\) 张优惠劵,剩余的钱就用原价购买 \(P\) 最小的奶牛。

然而这个贪心不一定全局最优。考虑使用优惠劵购买的奶牛 1 和原价购买的奶牛 2,以上贪心策略只能保证 \(C_1<C_2\)。假如 \(C_1+P_2 > P_1+C_2\),那么把奶牛 1 的优惠劵给奶牛 2 是更优的。

直观地看,\(C_1+P_2 > P_1+C_2\) 等价于 \(P_2-C_2 > P_1-C_1\),我们发现 \(P_i-C_i\) 这个值代表了把奶牛 i 从使用优惠劵购买转到不使用优惠劵购买的花费。这个值体现了该张优惠劵的使用效率,\(P_i-C_i\) 越大,表明使用优惠劵购买奶牛 i 的效率越高。

换一种贪心思路,我们只以 \(P_i-C_i\) 为关键字排序,从大到小选取奶牛。这个思路的错误也很显然。只需要构造一个 \(P_i\) 和 \(C_i\) 都很大而且相差很大的奶牛用光经费就行了。

那我们既想保证尽可能选取价格便宜的奶牛,又想保证每张优惠劵都能物尽其用,怎么做?

为了随时换用最不划算的优惠劵,我们将“使用优惠劵的价格”扔进小根堆。初始所有优惠劵未被使用,我们认为价格都为 \(0\)。当使用优惠劵购买了奶牛 i,我们把使用这张优惠劵的价格更改为 \(P_i-C_i\),这个值是下一个抢夺这张优惠劵的奶牛把奶牛 i 换成原价购买的花费。

为了尽可能选取价格便宜的奶牛,我们将每个 \(P_i\) 和 \(C_i\) 都扔进小根堆。每次取出没有被购买的最便宜的原价奶牛、优惠奶牛。比较原价奶牛的价格、优惠奶牛的价格加上最小的使用一张优惠劵的价格,取更为便宜的方案,直到钱用完为止。初始我们肯定会使用没有被使用过、价格为 \(0\) 的优惠券。随着优惠劵被使用,我们会逐渐把优惠劵转让给 \(P_i-C_i\) 更小的奶牛,确保优惠劵得到最有效的利用。这样可以保证价格更低的奶牛被优先选中,而每张优惠劵都被分配给最优的奶牛。

时间复杂度 \(O(N \log N)\)。

#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
using namespace std;
const int N=5e4+5;
int n,k,m,p[N],c[N];
int vis[N];
priority_queue<pii,vector<pii>,greater<pii>> P,C;
priority_queue<int,vector<int>,greater<int>> off;
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	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}); 
	}
	for(int i=1;i<=k;i++) off.push(0);
	int ans=0;
	while(m>=0&&ans<n)
	{
		auto [p1,id1]=P.top();
		auto [c2,id2]=C.top();
		int mi=off.top();
		if(vis[id1])
		{
			P.pop();
			continue;
		}
		if(vis[id2])
		{
			C.pop();
			continue;
		}
		if(c2+mi>=p1)
		{
			vis[id1]=1;
			m-=p1;
			P.pop();
		}
		else
		{
			vis[id2]=1;
			m-=c2+mi;
			off.pop();
			off.push(p[id2]-c[id2]);
			C.pop();
		}
		if(m>=0) ans++;
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2026-09-15 17:20  tai_chi  阅读(11)  评论(0)    收藏  举报