codevs 2382 [CSTC2007] 挂缀 贪心

18 篇文章 0 订阅
8 篇文章 0 订阅

题目:

http://codevs.cn/problem/2382/

这道题很难;

思路:
设a挂缀承受能力为ca,重量为wa,
b挂缀承受能力为cb,重量为wb,

设x为a,b下面的挂缀总重量;

若a在b上面更好(剩余承受能力更多),即:a.c-b.w-x > b.c-a.w-x;
移项得 a.c+a.w > b.c+b.w;
令d=(承受能力+重量)
所以,我们需要对每种挂缀的d进行排序;

然后,我们发现这仅仅只是一个贪心的方向;
若a.d>b.d,则a未必在b上面,因为a的承受能力可能比b小;

结合题目要求,最终输出最小重量;

有没有DP的感觉?

但是,这显然不是DP,因为数据范围太大,显然是小于O(nlogn)的做法;

所以,还要考无敌的贪心;

维护一个堆,像http://blog.csdn.net/qq_36312502/article/details/78249623那样做就可以了;
注意我们由小及大,所以考虑从下往上组成这个挂缀,这样就可以由大的更新小的了;

题外话:
这题我连WA五遍,然后改了半个小时;
最后发现没有将调试时写的代码去干净,QAQ!

堆的基本操作为O(logn),最多执行n次,排序为O(nlogn),

所以总复杂度为O(nlogn);

总结:
1.这是一类贪心题型,即在当前答案不变的情况下,尽可能使花费变小,让以后的状态更优;

2.细节!细节!去干净调试代码!

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;

typedef long long ll;

const ll MAXN=400001;
ll cnt=0,sum=0,n;
struct hh {ll c,w,d;}ma[MAXN];

bool operator < (hh a,hh b)
{
    return a.w < b.w;
}
priority_queue<hh>q;


bool cmp(hh a,hh b)
{
    return a.d < b.d;
}

void calc()
{
    for(ll i=1;i<=n;i++)
    {
        if(ma[i].c>=sum)
            cnt++,sum+=ma[i].w,q.push(ma[i]);
        else
        {
            if(q.empty()) continue;
            hh u=q.top();
            if(u.w > ma[i].w)
            q.pop(),sum-=u.w,sum+=ma[i].w,q.push(ma[i]);//因为i.d>u.d,而i.w<u.w,所以i.c>u.c,所以不用担心i无法承受u下面挂缀的情况;
        }
    }

    return;
}

void solve()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld%lld",&ma[i].c,&ma[i].w);
        ma[i].d=ma[i].c+ma[i].w;
    }

    sort(ma+1,ma+n+1,cmp);

    calc();

    cout<<cnt<<endl<<sum<<endl;
}


int main()
{
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值