[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 }