2018年9月15日提高组模拟赛 T1 购物

版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/82713685

大意

给定 n 件商品,现在你有 k 张降价券,可以让 a i 降至 b i 在购买金额不超过 m 最多能购买的物品数量


思路

首先显然可以发现,用降价券是永远比不用要好的,所以我们在一开始优先选择让降价后代价更低的,然后再依次补上,这种算法是存在漏洞的,所以只能拿80分


若要拿一百分,通过观察发现,有的时候一些本价本来就很低的商品用降价券是有点浪费的,我们完全可以话费 的代价换一张降价券给另一件没有被降价的商品,而显然另一件商品的代价必须要小于之前我们说的代价才能交换


这就是一种新的思想,可撤销贪心!

代码

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;int n,k,p[150001],q[150001],nused;long long m;
bool used[150001];
struct node{long long num;int id;};
priority_queue<node>qp,qq;
priority_queue<long long,vector<long long>,greater<long long> >cz;
inline bool operator <(node x,node y){return x.num>y.num;}//按照价值从小到大排
signed main()
{
    cin>>n>>k>>m;
    for(register int i=1;i<=n;i++) scanf("%d%d",p+i,q+i),qp.push((node){p[i],i}),qq.push((node){q[i],i});//qp为降价前的,qq为降价后的
    for(register int i=1;i<=k;i++) cz.push(0ll);//cz为差值,我们一开始假设所有的差值为0,这样也就是假设所有能用降价券的商品都用了降价券
    while(m>0&&nused<n)
    {
        while(used[qq.top().id]) qq.pop();
        while(used[qp.top().id]) qp.pop();//如果这些商品已经买走了则弹出
        if(cz.top()+qq.top().num<qp.top().num)//若差价是要下于另一件商品的原价的,把优惠券给另一件商品
        {
            node x=qq.top();
            long long cost=cz.top()+x.num;//计算代价
            if(m<cost) break;//买不起就退出吧
            m-=cost;//买了
            cz.pop();
            cz.push(p[x.id]-q[x.id]);//新增差值
            used[x.id]=true;//标记已经买了
        }
        else//否则不换
        {
            node x=qp.top();
            long long cost=x.num;//直接把这个商品买走
            if(m<cost) break;//买不起别买了
            m-=cost;//买走
            used[x.id]=true;//标记已经被买走了
        }
        nused++;//多买了一件
    }
    printf("%d",nused);//输出
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/82713685