ZOJ 3916 Buy Cakes (贪心+优先队列维护)

Description

Andy is always a hungry man. He never stopped eating something sweet, expecially cakes.

Yesterday his mother gave him some pocket money, and now, he has M dollars all together.

The cake shop provides N pieces of cakes, and each of them costs ai dollars respectively.

Fortunately, Andy has K discount coupons for that cake shop. When we use a coupon, we can buy a cake at a lower prize of bi dollars instead of the original ai dollars.

So, Andy wants you to help him find out how many cakes he can buy at most.

Input

There are multiple cases.

The first line contains the number of cases for this problem T (1<=T<=10).

For each case, the first line contains three integers N (1<=N<=105), K (0<=K<=N), and M (0<=M<=1014).

For next N lines, each line has two integers ai and bi (1<=bi<=ai<=109).

Output

For each case, output the number of cakes he can get at most.

Sample Input

2
4 1 7 
3 2 
2 2  
8 1  
4 3 
2 0 3
5 4
6 3

Sample Output

3
0

Hint

One of the solution for first case of sample input is to choose candy 1, 2, 3, and use the coupon on candy 3.

先考虑用完k张优惠券,即将所有的商品按照b排序,从小到大的k个。

如果sum>=M,则就只需要从小到大买。

否则,我们考虑着k个商品是否必须买。

假设a1,b1为k个商品中的一个商品,有a2,b2为除k个商品中的一个。

如果给1用优惠券,后面的商品中不可能有b小于b1,所以不可能有另一个商品优于1。

如果不给1用优惠券,则1的优惠券给了另一个商品使用,假设为2。

此时,花费a1+b2<b1+a2,如果我用另外一个商品3替换掉1,同样是2个商品,总花费是a3+b2,显然大于a3+b1,所以如果替换也是替换2,所以前k个商品取。

已经有了前k个商品,考虑下一个商品。

有一种选择是这种商品用优惠券,则之前用优惠券的商品需要有一个不用优惠券,所以对于已用优惠券的商品的优惠额   d=a-b用优先队列维护,cost=bi+min d   

另一种选择是不用优惠券,cost =aj

比较两个值,取小的一个,如果用优惠券,将新的a-b加入队列,去掉之前的队首,即可。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<stdio.h>
#include<functional>
#include<queue>
using namespace std;
struct node
{
    int a,b,id;
}p[100005],x[100005],y[100005];
int n,k;
int use[100005];
bool cmp1(node a,node b)
{
    if(a.a==b.a) return a.b<b.b;
    return a.a<b.a;
}
bool cmp2(node a,node b)
{
    if(a.b==b.b) return a.a<b.a;
    return a.b<b.b;
}
long long m;
int main()
{
    int T,i,j;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%lld",&n,&k,&m);
        priority_queue<int,vector<int>,greater<int> > q;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&p[i].a,&p[i].b);p[i].id=i;
            x[i]=y[i]=p[i];
        }
        memset(use,0,sizeof(use));
        sort(x+1,x+1+n,cmp1);
        sort(y+1,y+1+n,cmp2);
        long long v=0;
        int ans=0;
        if(k==0)
        {
            for(i=1;i<=n;i++)
            {
                v+=x[i].a; if(v>m) break;
            }
            i--;
            cout<<i<<endl;
            continue;
        }
        for(i=1;i<=k;i++)
        {
            use[y[i].id]=1;
            v+=y[i].b;
            ans++;
            if(v>m) {ans--;break;}
            q.push(y[i].a-y[i].b);
        }
        if(v>m) {printf("%d\n",ans);continue;}
        i=k+1;
        j=1;
        while(v<=m)
        {
            while(use[x[j].id]&&j<=n) j++;
            while(use[y[i].id]&&i<=n) i++;
            int c1,c2;
            if(i>n&&j>n) break;
            c1=x[j].a;
            int tp=q.top();
            c2=y[i].b+tp;
            if(c1<c2)
            {
                v+=c1;
                use[x[j].id]=1;
                ans++;
            }
            else
            {
                v+=c2;
                q.pop();
                q.push(y[i].a-y[i].b);
                use[y[i].id]=1;
                ans++;
            }
        }
        if(v>m) ans--;
        cout<<ans<<endl;

    }
    return 0;
}


你可能感兴趣的:(ZOJ 3916 Buy Cakes (贪心+优先队列维护))