【CTSC2007】挂缀 贪心

题目描述 Description

“珠缀花蕊,人间几多酸泪”……
挂缀在很早就被人们作为一种装饰品,垂坠的风韵,华丽摇曳的摆动,展现出一种与众不同的优雅与高贵。而我们的主人公小Q,正想买一条漂亮的挂缀放在寝室里作为装饰。
挂坠的构成,是由若干粒缀珠相互连接而成。每一个缀珠由三部分组成:分别是珠子、珠子上方的连接环与珠子下方的挂钩(如下图) 。我们可以简单的认为从上往下数的第 i 个缀珠是将它的连接环套在其上方(也就是第 i-1 个)缀珠的挂钩之上(第一个除外) 。小 Q想买一根足够长的挂缀,这样显得更有韵味☺

然而商店的老板告诉小Q,挂缀是不可能做到任意长的,因为每一个珠子都受到重力作用,对其上方的挂钩有一定的拉力,而挂钩的承受能力是有限的。老板还告诉小 Q,他一共拥有 N 个珠缀(假设每一个珠缀都很漂亮,小 Q 都很喜欢) ,每个珠缀都有其各自的重量与承受能力。一个挂缀是稳定的,当且仅当对于其上的每一个珠缀,它下方所有珠缀的重量和(不包含自身)不超过其挂钩的承受能力。
小Q希望她的挂缀尽量长,你能帮她计算出最长可能的稳定挂缀么?当然,如果有多个可选方案,小Q希望总重量最小的。

输入描述 Input Description

第一行包含一个正整数 N,表示商店拥有的珠缀数目。
接下来 N行,每行两个整数(Ci , Wi),分别表示第i 个珠缀的承受能力与重量。

输出描述 Output Description

包行两行。第一行包含一个整数L,表示可以找到的最长稳定挂缀长度。

第二行包含一个整数 W,表示可以找到的长度为 L 的稳定挂缀中的最小重量和。

样例输入 Sample Input

4
3 5
5 1
3 2
4 6

样例输出 Sample Output

3
8

数据范围及提示 Data Size & Hint

对于 30%的数据,N ≤ 10000;
对于 100%的数据,N ≤ 200000;
对于所有的数据,Wi, Ci不超过 231


设两个相邻珠缀分别为 <w1,c1>,<w2,c2> <script type="math/tex" id="MathJax-Element-2012"> , </script>底下的挂缀总重为W。

则这样满足两组式子:

若1挂在2上面,则: c1>=w2+wc2>=w
若2挂在1上面,则: c2>=w1+wc1>=w

其中每个情况第二个式子不用管……不管怎么挂,都会满足这个情况。

若1挂在2上面更优,则 c1(w2+w)>c2(w1+w) ,即 c1+w1>c2+w2
若2挂在1上面更优,则 c2(w1+w)>c1(w2+w) ,即 c2+w2>c1+w1

贪心的思想,留更多的重量来挂别的珠缀。

这样我们只要降序排列即可。然而这样很不好处理,每加一个珠缀就要看和前面的比是否超重,会提高复杂度。我们升序排列,每次看当前的承重是否能承受住当前重量,这样就成O(1)的了。

这样就可以证明:最优序列必定是当前序列的子序列。

设当前重量是W,则可以这样:

ci>=W ,则可以把当前珠缀连到答案中。
ci<Wwi<wj ,则可以把当前珠缀替换掉历史的那个珠缀。

这样就成了那个经典的贪心,一个堆维护。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const LL SIZE=200010;
const LL INF=20000000000000233ll;
struct guazhui{
    LL c,w;
}l[SIZE];

bool cmp(guazhui a,guazhui b)
{
    return a.c+a.w<b.c+b.w;
}

priority_queue<LL> q;

int main()
{
    LL n;
    scanf("%lld",&n);

    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&l[i].c,&l[i].w);
    }
    sort(l+1,l+1+n,cmp);

    LL tot=0;

    for(int i=1;i<=n;i++)
    {
        if(l[i].c>=tot) q.push(l[i].w),tot+=l[i].w;
        else if(l[i].w<q.top()) tot-=q.top(),tot+=l[i].w,q.pop(),q.push(l[i].w);
    }

    printf("%lld\n%lld\n",(LL)q.size(),tot);
    return 0;
}
/*
g++ codevs2382.cpp -o codevs2382.exe
*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值