首页 > 技术文章 > [Usaco 2012 Feb]Cow coupons牛券:反悔型贪心

hzoi-DeepinC 2019-10-09 20:21 原文

Description

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<=$P_i$<=$10^9$).FJ有K张优惠券,使用优惠券购买第i头奶牛时价格会降为Ci(1<=$C_i$<=$P_i$),每头奶牛只能使用一次优惠券。FJ想知道花不超过M(1<=M<=$10^{14}$)的钱最多可以买多少奶牛$

 

很久很久很久以前的一道题,当时真的不会做。

我也不知道当时他们怎么A的。当时好像没学反悔型贪心啊。。。

最近被贪心虐的不轻,又除了一个变种:反悔型的。

需要稍微写一些了。啊啊啊教练我真的没有在水题啊我真不会

认真的讲,这题不错,很经典的反悔

反悔型贪心的特点就是当前获得的收益到时候可以再返还来得到更长远的收益,这就克服了贪心的目光短浅的弊端。

在这道题里,我们反悔的主要原因就是优惠券的应用。

最开始我们买下k头用了优惠券后最便宜的牛,这是初步贪心。

如果我们连这k头都买不起的话直接跳出就好了。

但是这样做的话我们用优惠券所省下的钱可能不是最多的

具体怎么反悔呢?其实我们的反悔就是要改变对优惠券的使用。

那么我们就花钱把优惠券买回来呗!

我们在买前k头牛的时候,把p-c加入一个小根堆,表示你要花多少钱才能再得到一张优惠券。

再开两个堆,把其它的牛存进去,分别存p和c。

然后不断采取最优决策:买回一张券再买一头折扣后的牛,或者不折扣地买一头牛。

不断取最便宜的。这样的话我们的贪心策略就正确了。

要注意为了防止牛买重了,所以c和p两个堆都要把牛的编号记下来,弹出时打上标记表示被买过。

这样就不会让一头牛被用券买了一次又没用券买了一次从而产生2的贡献。

要注意所有的牛都买完之后及时跳出。。。

细节还是挺多的。当时没A就对了。

好题。

 1 #include<cstdio>
 2 #include<queue>
 3 #include<algorithm>
 4 using namespace std;
 5 priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >cow,discounted_cow;
 6 priority_queue<int,vector<int>,greater<int> >coupon;
 7 int n,k,p[50005],c[50005];pair<int,int>r[50005];long long m;char al[50005];
 8 int main(){
 9     scanf("%d%d%lld",&n,&k,&m);
10     for(int i=1;i<=n;++i)scanf("%d%d",&p[i],&c[i]),r[i]=make_pair(c[i],i);
11     sort(r+1,r+1+n);
12     for(int i=1;i<=k;++i){
13         if(m<r[i].first){printf("%d\n",i-1);return 0;}
14         m-=r[i].first;coupon.push(p[r[i].second]-r[i].first);al[r[i].second]=1;
15     }
16     for(int i=1;i<=n;++i)if(!al[i])
17         cow.push(make_pair(p[i],i)),discounted_cow.push(make_pair(c[i],i));
18     int ans=k;
19     while(ans<n){
20         if(coupon.top()+discounted_cow.top().first<cow.top().first){
21             if(coupon.top()+discounted_cow.top().first>m){printf("%d\n",ans);return 0;}
22             m-=coupon.top()+discounted_cow.top().first;
23             int ord=discounted_cow.top().second;
24             al[ord]=1;coupon.pop();coupon.push(p[ord]-c[ord]);
25             ans++;
26         }else{
27             if(cow.top().first>m){printf("%d\n",ans);return 0;}
28             m-=cow.top().first;al[cow.top().second]=1;ans++;
29         }
30         while(!discounted_cow.empty()&&al[discounted_cow.top().second])discounted_cow.pop();
31         while(!cow.empty()&&al[cow.top().second])cow.pop();
32     }printf("%d\n",n);
33 }
View Code

 

推荐阅读