P3045 [USACO12FEB]Cow Coupons G

                        P3045 [USACO12FEB]Cow Coupons G

[USACO12FEB]Cow Coupons G - 洛谷0a7b8f55fbea41bbb6706f58d8b86928.png

思路:我们首先根据c的大小排序,那么前k个如果可以买则一定买,如果不可以买说明钱一定不够了,因为后面的一定比前面的大;如果前k个能够都买了,那么我们在将考虑买后面的n-k个,我们需要维护三个队列,一个q1是前k个的p与c的差值,两外两个q2是n-k个的所有c,q3是n-k个的所有的p,三个都是小根堆,我们分别取出q2与q3的堆顶,如果我们买q2的话,说明我们现在要用一个优惠卷,但是我们前面买k个的时候已经用完了,如果继续使用就需要补上以前买过的牛的差价,所以它需要加上的是q2.top+q1.top,而q3的话就是直接按照原价买,所以就是分情况讨论哪一个更小用哪一个,同时需要更新q1,q2,q3,还要把用过的打上标记,防止在q2种使用了,在q3中再使用

#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#include<unordered_map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<set>
#include<cstdlib>
#include<stack>
#include<ctime>
#define forin(i,a,n) for(int i=a;i<=n;i++)
#define forni(i,n,a) for(int i=n;i>=a;i--)
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
typedef pair<pair<int,int>,int> PIII;
const double eps=1e-7;
const int N=5e4+7,M=2*N , INF=0x3f3f3f3f,mod=1e9+7;
inline ll read() {ll x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=(ll)x*10+c-'0';c=getchar();} return x*f;}
void stin() {freopen("in_put.txt","r",stdin);freopen("my_out_put.txt","w",stdout);}
void hack() {printf("\n----------------------------------\n");}
bool cmp(int a,int b) {return a>b;}
int hackT;
template<typename T> T gcd(T a,T b) {return b==0?a:gcd(b,a%b);}
template<typename T> T lcm(T a,T b) {return a*b/gcd(a,b);}

int T;
ll n,m,k;
bool st[N];
struct Node{
	int p,c;
	bool operator < (const Node &k) const {
		return c<k.c;
	}
};

Node w[N];

void solve() {  
	n=read(),k=read(),m=read();
	
	for(int i=1;i<=n;i++) w[i].p=read(),w[i].c=read();
	
	sort(w+1,w+1+n);
	
	priority_queue<int,vector<int>,greater<int> > q1;
	priority_queue<PII,vector<PII>,greater<PII> > q2,q3;
	
	int ans=0;
	for(int i=1;i<=k;i++) {
		if(m-w[i].c>=0) {
			m-=w[i].c;
			ans++;
		}
		q1.push(w[i].p-w[i].c);
	}
	
	for(int i=k+1;i<=n;i++) {
		q2.push({w[i].c,i});
		q3.push({w[i].p,i});
	}
	
	for(int i=k+1;i<=n;i++) {
		auto a=q2.top();
		while(q2.size()&&st[a.second]) {
			q2.pop();
			a=q2.top();
		}
		auto b=q3.top();
		while(q3.size()&&st[b.second]) {
			q3.pop();
			b=q3.top();
		}
		
		int x=a.first+q1.top();
		int y=b.first;
		
		if(x>y) {
			if(m-y>=0) {
				m-=y;
				ans++;
				st[b.second]=true;
				q3.pop();
			}else break;
		}else {
			if(m-x>=0) {
				m-=x;
				ans++;
				q2.pop();
				q1.pop();
				q1.push(w[a.second].p-w[a.second].c);
				st[a.second]=true;
			}else break;
		}
	}
	
	printf("%d\n",ans);
}

int main() {
    // init();
    // stin();
        
//    scanf("%d",&T);
    T=1; 
    while(T--) hackT++,solve();
    
    return 0;       
}          

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值