浅析拯救小矮人的 nlogn 算法及其证明
浅析拯救小矮人的 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 算法及其证明的更多相关文章
- 【BZOJ-3174】拯救小矮人 贪心 + DP
3174: [Tjoi2013]拯救小矮人 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 686 Solved: 357[Submit][Status ...
- 2075 yh女朋友的危机、2544 拯救小矮人
Codevs2075和2544是一道题,直接A过. 2075 yh女朋友的危机 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 ...
- BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP
BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀 ...
- 【BZOJ3174】[TJOI2013]拯救小矮人(贪心,动态规划)
[BZOJ3174][TJOI2013]拯救小矮人(贪心,动态规划) 题面 BZOJ 洛谷 题解 我们定义一个小矮人的\(A_i+B_i\)为它的逃跑能力. 我们发现,如果有两个小矮人\(x,y\), ...
- 贪心+DP【洛谷P4823】 [TJOI2013]拯救小矮人
P4823 [TJOI2013]拯救小矮人 题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以 ...
- [luogu] P4823 [TJOI2013]拯救小矮人(贪心)
P4823 [TJOI2013]拯救小矮人 题目描述 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以 ...
- BZOJ3174. [TJOI2013]拯救小矮人(dp)
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=3174 题解 其实此题并不需要那么多YY的部分. 我们考虑若干个小矮人逃出的顺序.若跳出的 ...
- BZOJ3174 Tjoi2013 拯救小矮人(贪心+DP)
传送门 Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个 ...
- bzoj3174 [Tjoi2013]拯救小矮人
Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口.对于每一个小矮人, ...
随机推荐
- Spring boot 自定义一个starter pom
用过springboot的自动配置会觉得非常方便,我们完全可以自己写一个starter pom,这样不仅可以有自动配置功能,而且具有更通用的的耦合度低的配置, 新建一个starter的maven项目, ...
- 红帽虚拟化RHEV-架构简介
目录 目录 软件环境 RHEV简介 RHEV与KVM的区别 RHEV的组成 RHEV-MManager RHEV-HHypervisor 虚拟机管理程序 存储 RHEV的架构 LDAPIPAAD We ...
- golang 千位分隔符
项目需求将统计出的数字以千位分隔符分隔的形式展示(如将 1234567.89 格式化为 1,234,567.89),而 golang 的标准库中并无这样的函数. 万能的 google 找到解决办法,可 ...
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'jeewx.weixin_account_user_relation' doesn't exist
[INFO] Scanning for projects...[INFO] [INFO] ------------------------------------------------------- ...
- 【Linux开发】直接渲染管理
原文地址:https://dri.freedesktop.org/wiki/DRM/ DRM - Direct Rendering Manager DRM是一个内核级的设备驱动,既可以编译到内核中也可 ...
- supervisor启动elk7.4.0组件
es [program:elasticsearch] command = /srv/app/elk/elasticsearch/bin/elasticsearch autostart = true s ...
- 第二章 Git
1.安装 这个就不必细说了 2.安装完后还要进行一步设置. 在命令行输入: git config --global user.name "Your Name" git config ...
- webView实现网页缩放
项目中遇到要实现webview上面的网页缩放功能,在网上查了资料加自己实践后得出结论: //缩放开关,设置此属性,仅支持双击缩放,不支持触摸缩放 mWebView.getSettings().setS ...
- linux中忘记mysql用户root密码解决方案
1.vim /etc/my.cnf[mysqld]skip-grant-tables ##追加此行,跳过权限表, 2.重启mysqlsystemctl restart mysqld 3.mysql 登 ...
- Python入门之 函数
Python入门之 函数 1.初识函数 1.1 什么是函数? <1> 将某个功能封装到一个空间中就是一个函数 <2> 减少重复代码 1.2 定义函数 def -- python ...