[Usaco2012 Feb]Cow Coupons 买牛 或 牛券

本人水平有限,题解不到为处,请多多谅解

本蒟蒻谢谢大家观看

题目:传送门

本题时带有反悔操作的贪心

我们可以先按优惠价给他们排序,可以保证序列值从小到大最优(优惠价比原价小)

取前k头奶牛(k张优惠券),但不一定会在它们身上用上优惠券之后我们可以用反悔操作但此时一定为最优,再用总钱数不断减去,若当总钱数<0时,我们不用继续往下找了,前k个数一定最小的,所以统计完之后直接return 掉

若取完前k头牛钱还有剩余的话,我们又分为两种情况

1:若k之后的当前点不用券,那就要维护一个原价sort,不断贪心

2:若k之后的当前点要有券,那么用差值维护一个小根堆,不断贪心

注意记得开long long

数据范围很大

code:

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3)
 3 #define int long long
 4 using namespace std; 
 5 const int INF=5e18;
 6 priority_queue<int,vector<int>,greater<int> >q;
 7 int ans=0,n,k,m,hhh;
 8 inline int read(){
 9     int x=0,f=1;char ch=getchar();
10     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
11     while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
12     return x*f;
13 }
14 struct oo{
15     int p,c;
16     bool use;
17 }cow[51000];
18 bool cmp1(oo aa,oo bb){
19     return aa.c<bb.c;
20 }
21 bool cmp2(oo aa,oo bb){
22     return aa.p<bb.p;
23 }
24 signed main()
25 {    
26     n=read(),k=read(),m=read();
27     for(int i=1;i<=n;i++){
28         cow[i].p=read(),cow[i].c=read();
29     }
30     sort(cow+1,cow+1+n,cmp1);//按优惠价排列贪心 
31     for(int i=1;i<=k;i++){
32         m-=cow[i].c;
33         if(m>=0){
34             ans++;
35         }
36         else{
37             printf("%lld\n",ans);
38             return 0;
39         }
40         q.push(cow[i].p-cow[i].c);//预处理反悔,方便赎回券 
41     }
42     sort(cow+1+k,cow+1+n,cmp2);//取完前k头牛之后的,按原价排列(无券可用) 
43     for(int i=k+1;i<=n;i++){
44         if(q.empty()){
45             hhh=INF;//如果堆为空,因为此题要求取min,所以初始最大化 
46         }
47         else{
48             hhh=q.top();//如果堆不为空,取出堆顶 
49         }
50         if(hhh+cow[i].c<cow[i].p){
51         //如果赎回一张券来用给j的话,判断反悔时赎金+使用券后的钱与不用券的值比 
52             m-=q.top()+cow[i].c;//如果小于,用券给j,记下小值 
53             q.pop();//出堆 
54             q.push(cow[i].p-cow[i].c);//继续贪心 
55             //因为取走了cow[i].p-cow[i].c 所以继续push进堆 
56         }
57         else{
58             m-=cow[i].p;//否则不用券给j,直接累加取最优 
59         }
60         if(m>=0){
61             ans++;//判断此时手上的钱是否大于0,大于0就表示可以买这头牛 
62         }
63         else{
64             printf("%lld\n",ans);//否则钱不够,后面肯定也买不起,直接break 
65             return 0;
66         }
67     }
68     printf("%lld\n",ans);//输出答案即可 
69     return 0;
70 }

猜你喜欢

转载自www.cnblogs.com/nlyzl/p/11697432.html
今日推荐