[USACO12FEB]牛券Cow Coupons (洛谷P3045)

[USACO12FEB]牛券Cow Coupons

题目描述

Farmer John needs new cows! There are N cows for sale (1 <= N <= 50,000), and FJ has to spend no more than his budget of M units of money (1 <= M <= 10^14). Cow i costs P_i money (1 <= P_i <= 10^9), but FJ has K coupons (1 <= K <= N), and when he uses a coupon on cow i, the cow costs C_i instead (1 <= C_i <= P_i). FJ can only use one coupon per cow, of course.

What is the maximum number of cows FJ can afford?

FJ准备买一些新奶牛,市场上有N头奶牛(1<=N<=50000),第i头奶牛价格为Pi(1<=Pi<=10^9)。 FJ有K张优惠券,使用优惠券购买第i头奶牛时价格会降为Ci(1<=Ci<=Pi),每头奶牛只能使用一次优惠券。FJ想知道花不超过M(1<=M<=10^14)的钱最多可以买多少奶牛?

输入格式

  • Line 1: Three space-separated integers: N, K, and M.

  • Lines 2…N+1: Line i+1 contains two integers: P_i and C_i.

输出格式

  • Line 1: A single integer, the maximum number of cows FJ can afford.

输入 #1

4 1 7
3 2
2 2
8 1
4 3

输出 #1

3

这道题思维真的强,建三个小根堆,一个维护原价,一个维护优惠价,一个维护 差价(原价 - 优惠价);刚开始建一个队列大小为k(优惠卷数目)的队列(就是维护差价的队列),并且全部设为0,说明这时优惠卷还没用完,差价为0;然后最关键的就是比较原价和差价+优惠价的大小,如果>,这说明这个优惠卷可以可以回退;如果<,说明直接原价买

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<LL,int>
using namespace std;
priority_queue< pa,vector<pa>,greater<pa> >h1,h2;
priority_queue< LL,vector<LL>,greater<LL> >h3;
LL p[50100],c[50100],m,sum;
bool v[50100];
LL ans;
int main(){
	int n,k;
	scanf("%d%d%lld",&n,&k,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld",&p[i],&c[i]);
		h1.push(pa(p[i],i));
		h2.push(pa(c[i],i));
	}
	for(int i=1;i<=k;i++) h3.push(0LL);
	while(!h1.empty()){
		pa n1=h1.top();
		pa n2=h2.top();
		if(v[n1.second]){
			h1.pop();
			continue;
		}
		if(v[n2.second]){
			h2.pop();
			continue;
		}
		if(n1.first<n2.first+h3.top()){//说明不用优惠卷,或者优惠卷用完了后的代价太大,不如直接买 
			if(sum+n1.first>m) break;
			ans++;
			sum+=n1.first;
			v[n1.second]=true;
			h1.pop();
		}
		else{//如果h3.top()不为0,说明优惠卷已经用完,这时只能回退优惠卷并承担代价 
			if(sum+n2.first+h3.top()>m) break;
			ans++;
			sum+=n2.first+h3.top();
			v[n2.second]=true;
			h3.push(p[n2.second]-c[n2.second]);//差价,相当于回退优惠卷时要返回的代价 
			h2.pop();
			h3.pop();
		} 
	}
	printf("%lld\n",ans); 
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值