P3045 题解
LengthCheng · · 题解
蒟蒻的第一篇题解
>> P3045 [USACO12FEB]Cow Coupons G
题目分析
读完题目,我们不难发现这是一道贪心题。接下来我们考虑贪心策略。
不难发现答案组成要么全部使用优惠券,要么一部分使用优惠券,一部分不使用优惠券。
因此,我们可以考虑先对
由于
接下来分析第二种情况,此时一定有
-
从第
k+1 到第n 只奶牛中选取一只P 值最小的奶牛w ,此时总钱数的增加量为P_w 。 -
从前
k 只奶牛中选取一只P 值与C 之差最小的奶牛a ,再从第k+1 到第n 只奶牛中选取一只C 值最小的奶牛b ,并将a 的优惠券给b 使用,此时总钱数的增加量为P_a - C_a + C_b 。
根据贪心的思想,我们应该使每次更新答案时总钱数的增加量尽可能的小,这样才能购买到尽可能多的奶牛,即总钱数的增加量应为
代码实现
可以开一个结构体数组存每只奶牛的
-
前
k 只奶牛的P 值与C 值之差。 -
第
k + 1 到第n 只奶牛的C 值。 -
第
k + 1 到第n 只奶牛的P 值。
然后遍历一遍第
-
第一个队列在某一时刻可能为空,此时不能使用第二种取法更新答案。
-
第二个队列的队首元素与第三个队列的队首元素可能属于同一只奶牛,由于每只奶牛只能购买一次,所以更新答案时要同时弹出三个队列的队首元素。
下面给出代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
typedef pair<int,int> paii;
priority_queue<paii,vector<paii>,greater<paii>> q1,q2,q3;
struct Cow{
int p;
int c;
};
Cow cow[N];
bool vst[N];
bool cmp(Cow a,Cow b)
{
return a.c<b.c;
}
int main(){
int n,k;
long long m;
cin>>n>>k>>m;
for(int i=1;i<=n;++i)
{
scanf("%d%d",&cow[i].p,&cow[i].c);
}
sort(cow+1,cow+n+1,cmp);
long long tot=0;
for(int i=1;i<=k;++i)
{
tot+=cow[i].c;
q1.push(make_pair(cow[i].p-cow[i].c,i));
if(tot>m)
{
printf("%d",i-1);
return 0;
}
}
for(int i=k+1;i<=n;++i)
{
q2.push(make_pair(cow[i].c,i));
q3.push(make_pair(cow[i].p,i));
}
for(int i=k+1;i<=n;++i)
{
int k1=q2.top().second,k2=q3.top().second;
int v1,v2=q3.top().first;
if(!q1.empty())
{
v1=q2.top().first+q1.top().first;
tot+=min(v1,v2);
}
else
{
tot+=v2;
}
if(tot<=m)
{
if(q1.empty())
{
if(k1==k2)
{
q2.pop();
}
q3.pop();
}
else
{
if(v1>=v2)
{
if(k1==k2)
{
q2.pop();
}
q3.pop();
}
else
{
if(k1==k2)
{
q3.pop();
}
q1.pop(),q2.pop();
}
}
}
else
{
printf("%d",i-1);
return 0;
}
}
printf("%d",n);
return 0;
}