codevs 2382 [CSTC2007] 挂缀 贪心

来源:互联网 发布:kyocera打印机驱动mac 编辑:程序博客网 时间:2024/06/11 02:20

题目:

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