浅析拯救小矮人的 nlogn 算法及其证明



题型简介:

有 $ n $ 个人,第 $ i $ 个人身高 $ a_i $ 手长 $ b_i $ ,他们为了从一个高为 $ H $ 的洞中出去,决定搭人梯。如果一个人和他下面的人的身高之和加上他的手长可以达到洞的高度,那么他就可以出去。求最多有多少人能出去。 $ n\leq 10^6 $



算法流程

本题需要贪心,所以我们可以贪心到底。首先我们将所有人,按照他们的最低逃生高度 $ H-a_i-b_i $ 从高到低排序。一个必须要知道的结论:最低逃生高度越高的人,一定越先走

首先我们将所有人按照 $ H-a_i-b_i $ (最低逃生高度)从高到低排序,根据结论越高的人越先走。然后如果是 $ n^2 $ 背包,就是对每个人做有条件的背包,模拟每个人是否能走。

而 $ n\times logn $ 的方法则是记录一个后缀 $ s[] $ ,其中 $ s[i] $ 表示第 $ i $ 个人后面最低逃生高度比他低的所有人的身高总和,然后用一个 $ tot $ 记录前面没有出去的人的身高总和,对于从高到低枚举的第 $ i $ 个人,如果 $ s[i]+tot>=H-a_i-b_i $ 就说明他能出去(于是默认他出去);否则就将这个人的身高和前面所有已经出去的人的身高作比较,如果当前这个人最高那么他就不出去了,不然就从前面已经出去的人里面找到那个最高的人,把他拉回洞里垫在下面,让当前这个人出去!照着这个过程做我们就能得到最优解。


算法证明:

其实这个算法只有两个待考究的地方,问题一:为什么最低逃生高度高的人,一定越先走?这个问题在很多题解里已经讨论过了,难以讲清,本题不做多讲,就用一张图感性一下:

本算法第二个问题在于这句话: 否则就将这个人的身高和前面所有已经出去的人的身高作比较,如果当前这个人最高那么他就不出去了,垫到下面去;不然就从前面已经出去的人里面找到那个最高的人,把他拉回洞里垫在下面,让当前这个人出去!为什么把上面最高的那个人拉下来,这个人就一定可以出去了?为什么只取一个人下来,我们可不可以拉多个人下来,让当前这个人出去的同时为后面的人垫高度?这个我们用两张图解读:



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set> #define ll long long
#define db double
#define rg register int using namespace std; int n,H; //人数;陷阱高度
int tot,ans; //之前没能逃生的人的身高总和;答案
int s[200005]; // s[i]表示在第i个人后面逃生的所有人的身高总和,就是后缀和
priority_queue<int> q; //用来求之前已经逃生的人中,身高最高的人 struct su{
int a,b,h,id; //身高,手长,最低逃生高度,编号
inline bool operator <(const su &i)const{
return h>i.h; //按最低逃生高度,从高到底排序
} //(其实说白了就是逃生能力排序,为了方便理解就详细一点)
}p[200005]; //存小矮人信息的数组 people inline int qr(){ //快读
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
} int main(){
n=qr();
for(rg i=1;i<=n;++i)
p[i].a=qr(),p[i].b=qr();
H=qr();
for(rg i=1;i<=n;++i){
p[i].h=H-p[i].a-p[i].b; //最低逃生高度
p[i].id=i; //每个人的编号
}
sort(p+1,p+n+1);
for(rg i=n;i>=1;--i)
s[i]=s[i+1]+p[i+1].a; //s[i]表示在第i个人后面逃生的所有人堆起来达到的高度
for(rg i=1;i<=n;++i){
if(tot+s[i]>=p[i].h) q.push(p[i].a), ++ans;
//如果在他前面不能逃生的人加上在他后面的人堆起来达到了他的最低逃生高度,就让他走
else{
if(!q.empty()&&q.top()>p[i].a){ //拿出之前最大的身高和他对比,较大的走
tot+=q.top();
q.pop(); --ans;
q.push(p[i].a); ++ans; //其实ans根本没变,为了高度还原就这样了
} else tot+=p[i].a; //否则这个就垫到下面去
}
}printf("%d\n",ans);
return 0;
}

浅析拯救小矮人的 nlogn 算法及其证明的更多相关文章

  1. 【BZOJ-3174】拯救小矮人 贪心 + DP

    3174: [Tjoi2013]拯救小矮人 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 686  Solved: 357[Submit][Status ...

  2. 2075 yh女朋友的危机、2544 拯救小矮人

    Codevs2075和2544是一道题,直接A过. 2075 yh女朋友的危机  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果   ...

  3. BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP

    BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀 ...

  4. 【BZOJ3174】[TJOI2013]拯救小矮人(贪心,动态规划)

    [BZOJ3174][TJOI2013]拯救小矮人(贪心,动态规划) 题面 BZOJ 洛谷 题解 我们定义一个小矮人的\(A_i+B_i\)为它的逃跑能力. 我们发现,如果有两个小矮人\(x,y\), ...

  5. 贪心+DP【洛谷P4823】 [TJOI2013]拯救小矮人

    P4823 [TJOI2013]拯救小矮人 题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以 ...

  6. [luogu] P4823 [TJOI2013]拯救小矮人(贪心)

    P4823 [TJOI2013]拯救小矮人 题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以 ...

  7. BZOJ3174. [TJOI2013]拯救小矮人(dp)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=3174 题解 其实此题并不需要那么多YY的部分. 我们考虑若干个小矮人逃出的顺序.若跳出的 ...

  8. BZOJ3174 Tjoi2013 拯救小矮人(贪心+DP)

    传送门 Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个 ...

  9. bzoj3174 [Tjoi2013]拯救小矮人

    Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个小矮人, ...

随机推荐

  1. leetcode-mid-sorting and searching - 240. Search a 2D Matrix II -NO

    mycode   time limited def searchMatrix(matrix, target): def deal(data): if not data: return False ro ...

  2. 二、robotframework接口测试-常用关键字介绍

    1.常用关键字介绍: a. 打印:log                                                  用法:log   打印内容 ---------------- ...

  3. django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.的解决办法

    如题,这个错误的解决办法如下: 在代码文件的最上方添加以下代码: import os,django os.environ.setdefault("DJANGO_SETTINGS_MODULE ...

  4. Apache hadoop namenode ha和yarn ha ---HDFS高可用性

    HDFS高可用性Hadoop HDFS 的两大问题:NameNode单点:虽然有StandbyNameNode,但是冷备方案,达不到高可用--阶段性的合并edits和fsimage,以缩短集群启动的时 ...

  5. 【Linux 应用编程】基础知识

    错误提示 Linux 提供的系统调用API,通常会在失败的时候返回 -1.如果想获取更多更详细的报错信息,需要借助全局变量 errno 和 perror 函数: #include <stdio. ...

  6. Web测试常用的链接测试工具

    1.Xenu Link Sleuth 详细解说地址:http://home.snafu.de/tilman/xenulink.htm http://pan.baidu.com/s/1qY3Tp4C(英 ...

  7. jmeter常用性能监听器分析

    jmeter中提供了很多性能数据的监听器,我们通过监听器可以来分析性能瓶颈 本文以500线程的阶梯加压测试结果来描述图表. 常用监听器 1:Transactions per Second 监听动态TP ...

  8. Hello World!----html

    ​ 最近要做一个小网站,今晚想起来还是先看看前端终于抑制住惰性,开始看了. ​ 看了一下html,写了个hello world.老实讲,我竟然还有些小激动 ​ <html> <hea ...

  9. 问题记录 | deepin15.10重装nvidia驱动及cuda

    问题描述: nvidia-smi也有显示,显卡驱动是在的,而且nvcc显示出来的cuda版本9.0也没错,不是9.1.不知道问题所在,索性重装全部. sudo tee /proc/acpi/bbswi ...

  10. Luogu p2456 二进制方程

    这是一道我也不知道我gu了多久的题目 (然鹅还有n多任务没有完成) 反正--我太难了 好了言归正传,题目链接 是一道校内测的题目(现在应该没有人没考了吧?) 思路的话,是神仙并查集√ 觉得虽然并查集很 ...