浅析拯救小矮人的 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-34 Search for a Range

    mycode   63.98% class Solution(object): def searchRange(self, nums, target): """ :typ ...

  2. maven依赖传递和排除依赖冲突

    1 依赖的传递 假如 A项目 依赖 a.jar 1.0.1,b.jar 1.0.1,没有直接依赖c.jar 1.0.1,但是b.jar 1.0.1依赖了c.jar 1.0.1,可以说A项目间接依赖了c ...

  3. FineReport打印方式(转)

    1. 报表打印机制 各种打印的运行机制,都是选择打印时,先根据报表内容,在服务器的内存中将页面中的内容全部生成完毕,即生成对应格式的对象:然后再由serverlet直接推送给客户端,最后根据选择的打印 ...

  4. 关于ajax请求controller返回中文乱码的解决方法!

    问题描述:前台ajax请求 Spring框架的 controller 返回的本应该是一段中文字符串 ,结果返回了一串 ?????? 解决办法:在RequestMapping的属性中添加返回数据类型属性 ...

  5. Jmeter测试HTTP接口

    一.工具说明 Jmeter是一款开源的桌面应用软件,可以用于进行接口测试和性能测试.因为该软件是开源的,所以更具扩展性.Jmeter可以对Web应用进行测试,另外还支持Java请求.Webservic ...

  6. windows 使用Docker Desktop 使用国内镜像

    ===新增一些比较给力的镜像=== 1.中科大镜像加速地址 https://docker.mirrors.ustc.edu.cn 2.阿里云镜像服务 ========= 原本在配置项中添加了:国内镜像 ...

  7. c++ 事件回调 java

    #pragma once #ifdef __cplusplus extern "C" { #endif typedef void(*sig_t)(int); int FirstEl ...

  8. unity让碰撞只发生一次

    碰撞发生在帧的开始,所以你可以检测到冲突,并在LateUpdate复位: private bool hasCollided = false; void OnCollisionEnter(Collisi ...

  9. Java与C#不同

    1.C#方法定义可以有默认参数,而Java则不支持该方式. C#方法定义 public void ShowMessage(string text,string orderId="" ...

  10. GCC 环境变量 & eclipse CDT 头文件配置

     转:http://blog.csdn.net/statdm/article/details/7751000 GCC 环境变量 & eclipse CDT 头文件配置   在unix 下使用e ...