洛谷 P1873 砍树 (二分 简单)

news2025/1/16 21:39:16

【二分答案】是分治的一种,这类问题很经典,接下来几篇文章会关于二分答案相关的文章,希望同学们可以完成10道以上的【二分答案】相关问题,以此来加深对【二分答案】这类问题的个人理解。
原公众号链接:分治第二讲:二分答案之砍树问题

一、题目

题目链接:

https://www.luogu.com.cn/problem/P1873

题意:找到一个最恰当的高度砍树,使得砍树得到的树木高度之和刚好大于等于M即可。看题目数据范围,1<=n<=10^6,通过这个数据范围,可以反推出你的算法时间复杂度只能是低于O(nlogn),因此瞬间想到二分,往二分上靠拢。

二、题目分析

题意很简单,如何求解呢?其实会发现,直接求解不是很容易求解,该问题可以归纳总结为【最小值最大问题】,即需要求解的砍树高度,在满足题目要求的情况下要最大。【最小值最大】和【最大值最小】问题均可以通过【二分答案】思路完成,在完成【二分】之前,我们先用暴力实现,然后再修改为二分即可。

对于任何一个问题,一般有两种方式解决,一种是直接求解,另一种是检验,检验指的是给一个可能解,带入题目中检查该解是否满足题目,检验类似于数学中的选择题,如果不会直接求解,那么可以依次把四个选项带入题目中检验验证即可;我个人认为:检验的难度小于直接求解。

该题目求解最恰当的砍树高度h,假设最高的那棵树的高度为maxH, 则h的取值范围为[0, maxH];可以依次让k从maxH开始依次递减直到0,递减过程中,如果某个取值恰当满足砍的树的高度之和大于等于M,则当前k就是最终解,直接输出并结束程序即可。

三、题目解决

上一部分分析了题目的求解方法并可以通过暴力的方法依次从maxH到0遍历,找到第一个满足题目要求的高度即可,试想一个问题,如果某个高度hi砍树不能满足砍掉的树的高度和大于等于M,那么对于大于等于hi的高度hj来说也无法满足题意,理解了上面这个特性就可以通过二分来快速求解高度h了。

二分的左边界left为0,右边界right为maxH,在这里扩展一个点,如果根据题意不好确定二分的初始边界left和right,那么可以直接暴力将left初始化为0,right初始化为一个很大的值,比如1e8;

Step1:取二分的中间值mid = left + (right-left)/2,检查以mid为砍树高度,是否可以得到高度大于等于M的树木;

Step2:如果不行,那么大于等于mid的高度均无法得到,因此缩小二分区间,right = mid-1;

Step3:如果可以,那么mid就是可能的一个解,保存在ans中,缩小二分区间,left = mid+1; (一定要记住,使用二分,禁止出现left = mid,因为这样很有可能陷入死循环,所以务必要避免left = mid,但是可以有right = mid);

二分问题解决了,如何实现检验函数check呢?也很简单,给你一个高度mid,遍历所有树木的高度,用sum记录砍掉的树的高度和,则如果当前树的高度小于mid,则没有得到树木,否则,在当前树上可以砍下树的高度减掉mid的差值的高度的树木,最终只需要判断sum是否大于M即可。

四、code编码

暴力代码O(n^2)


#include "iostream"
using namespace std;
const int M = 1000010;
int n, m, a[M], l = 0, r = -1, ans = -1;

// check函数的功能是:给一个高度x,返回该高度是否可以砍出高度和为m的树木,如果可以返回true,否则返回false
bool check(int x) {
  long long sum = 0;
  for(int i=1; i<=n; i++) {  // 遍历所有树木
    sum += max(0, a[i]-x);  // 求解x的高度,每个树可以砍多少树木
  }
  return sum >= m;   // 砍出的总和是否大于m,如果大于m则返回true,否则返回false;
} 

int main() {
  cin >> n >> m;
  for(int i=1; i<=n; i++) {
    cin >> a[i];
    r = max(r, a[i]);  // 确定右边界,为最高的树的高度
  }
  for(int x = r; x>=l; x--) {
    if(check(x)) {  
      cout << x << endl;
      return 0;
    }
  }
  
}

暴力超时6个点,AC了4个点,因此通过二分优化如下:

二分代码O(nlogn)


#include "iostream"
using namespace std;
const int M = 1000010;
int n, m, a[M], l = 0, r = -1, ans = -1;

// check函数的功能是:给一个高度x,返回该高度是否可以砍出高度和为m的树木,如果可以返回true,否则返回false
bool check(int x) {
  long long sum = 0;
  for(int i=1; i<=n; i++) {  // 遍历所有树木
    sum += max(0, a[i]-x);  // 求解x的高度,每个树可以砍多少树木
  }
  return sum >= m;   // 砍出的总和是否大于m,如果大于m则返回true,否则返回false;
} 

int main() {
  cin >> n >> m;
  for(int i=1; i<=n; i++) {
    cin >> a[i];
    r = max(r, a[i]);  // 确定右边界,为最高的树的高度
  }
  while(l <= r) {  // 二分答案
    int mid = l + (r-l)/2;  // 找出区间的中间值
    if(check(mid)) {  // 如果当前mid高度可以砍出m的树木高度,则说明mid是一个可能解,保存并缩小区间
      ans = mid;  // 保存可能解
      l = mid + 1; // 缩小区间
    } else {
      r = mid-1;  // mid高度不行,因此需要缩小右边界,答案在左区间
    }
  }
  cout << ans;
  
}

二分细节是魔鬼呀,琢磨什么时候是while(left<right),什么时候是while(left <= right)?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1358182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pygame学习(二)——绘制线条、圆、矩形等图案

导语 pygame是一个跨平台Python库(pygame news)&#xff0c;专门用来开发游戏。pygame主要为开发、设计2D电子游戏而生&#xff0c;提供图像模块&#xff08;image&#xff09;、声音模块&#xff08;mixer&#xff09;、输入/输出&#xff08;鼠标、键盘、显示屏&#xff09;模…

stable diffusion 基础教程-提示词之光的用法

基图 prompt: masterpiece,best quality,1girl,solo,looking at viewer,brown hair,hair between eyes,bangs,very long hair,red eyes,blush,bare shoulders,(white sundress),full body,Negative prompt: EasyNegative,badhandv4,nsfw,lowres,bad anatomy,bad hands,text…

Linux第14步_安装FTP服务器

安装“vim编辑器”后&#xff0c;我们紧接着“安装FTP服务器”。 1、在安装前&#xff0c;要检查虚拟机可以上网&#xff0c;否则可能会导致安装失败。 2、在虚拟机界面右击鼠标&#xff0c;弹出下面的对话框 3、点击“打开终端(E)”&#xff0c;得到下面的界面 &#xff1a;…

YOLOv7独家原创改进:新颖的Shape IoU结合 Inner-IoU,基于辅助边框的IoU损失的同时关注边界框本身的形状和尺度,小目标实现高效涨点

💡💡💡本文改进:一种新的Shape IoU方法结合 Inner-IoU,基于辅助边框的IoU损失的同时,更加关注边界框本身的形状和尺度来计算损失 💡💡💡对小目标检测涨点明显,在VisDrone2019、PASCAL VOC均有涨点 💡💡💡本文改进:一种新的Shape IoU方法,该方法可以通过…

使用“反向代理服务器”的优点是什么?

反向代理服务器是一种网络架构模式&#xff0c;通常位于客户端和实际服务器之间&#xff0c;用于处理客户端请求并转发到实际服务器。以下是使用反向代理服务器的优点&#xff1a; 1.安全性&#xff1a;反向代理服务器可以提供额外的安全层。通过在反向代理服务器上配置防火墙和…

Linux-故障排查

实验要求 samba仅允许192.168.1.0/24、192.168.10/24进行访问 开一台虚拟机 快照恢复到未联网安装 关闭防火墙 安全linux 编辑ens33网卡 vim /etc/sysconfig/network-scripts/ifcfg-ens33 将ens33网卡复制一份命名为ens37 cp /etc/sysconfig/network-scripts/ifcfg-ens33 /etc…

Unity 点击对话系统(含Demo)

点击对话系统 可实现点击物体后自动移动到物体附近&#xff0c;然后弹出对话框进行对话。 基于Unity 简单角色对话UI脚本的编写&#xff08;新版UI组件&#xff09;和Unity 关于点击不同物品移动并触发不同事件的结合体&#xff0c;有兴趣可以看一下之前文章。 下边代码为U…

MATLAB - MPC - 优化问题(Optimization Problem)

系列文章目录 前言 模型预测控制可在每个控制间隔内解决一个优化问题&#xff0c;具体来说就是二次规划(QP)。求解结果决定了被控对象在下一个控制间隔之前使用的操纵变量&#xff08;MV&#xff09;。 该 QP 问题具有以下特点&#xff1a; 目标或 "成本 "函数 - …

【数据库】CRUD常用函数UNION 和 UNION ALL

文章目录 一、CRUD二、函数2.1 字符函数 (Character Functions):2.2 数字函数 (Numeric Functions):2.3 日期函数 (Date Functions):2.4 流程控制函数:2.5 聚合函数: 三、UNION 和 UNION ALL3.1 UNION&#xff1a;3.2 UNION ALL3.3 注意事项 一、CRUD CRUD 是指数据库操作的四…

【RabbitMQ】1 消息中间件MQ概述

目录 什么是消息中间件为什么使用消息中间件流量削峰应用解耦异步处理 主流消息中间件及选型选取原则RabbitMQRocketMQKafka如何选择 消息中间件应用场景电商秒杀案例拉勾B端C端数据同步案例支付宝购买电影票 什么是消息中间件 维基百科对消息中间件的解释&#xff1a;面向消息…

JVM之内存模型带参数

Spring Boot程序的JVM参数设置格式(Tomcat启动直接加在bin目录下catalina.sh文件里)&#xff1a; java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize256M ‐XX:MaxMetaspaceSize256M ‐jar xxxxxx.jar-Xss&#xff1a;每个线程的栈大小 -Xms&#xff1a;设置…

Prototype原型模式(对象创建)

原型模式&#xff1a;Prototype 链接&#xff1a;原型模式实例代码 注解 模式定义 使用原型实例指定创建对象的种类&#xff0c;然后通过拷贝这些原型来创建新的对象。 ——《设计模式》GoF 目的 在软件系统中&#xff0c;经常面临这“某些结构复杂的对象”的创建工作&am…

3D Gaussian Splatting复现

最近3D Gaussian Splatting很火&#xff0c;网上有很多复现过程&#xff0c;大部分都是在Windows上的。Linux上配置环境会方便简单一点&#xff0c;这里记录一下我在Linux上复现的过程。 Windows下的环境配置和编译&#xff0c;建议看这个up主的视频配置&#xff0c;讲解的很细…

led台灯哪些牌子性价比高?那些性价比高的LED护眼台灯推荐

台灯作为家居用品在日常生活中使用频繁。用户可以根据个人需求和喜好&#xff0c;在市场上找到合适的款式。然而&#xff0c;由于台灯种类繁多&#xff0c;甚至连相关标准都存在差异&#xff0c;这使得一些缺乏经验的购物小白感到困扰。那么&#xff0c;led台灯哪些牌子性价比高…

python入门,list列表详解

目录 1.list的定义 2.index查找某元素的下标 3.修改 ​编辑 4.插入 ​编辑 5.追加元素 1.append,追加到尾部 2.extend,追加一批元素 ​编辑 6.删除元素 1.del 列表[下标] 2.列表.pop(下标) 3.列表.remove(元素) 7.清空列表 8.统计某一元素在列表内的数量 9.计算…

app广告变现——广告预加载机制,提升用户体验

通过广告预加载&#xff0c;开发者可以避免在向用户显示广告时出现延迟。 应用在程序启动时需要请求网络&#xff0c;加载资源会需要等待时间&#xff0c;如果在等待过程中没有及时给用户展现画面或反馈&#xff0c;用户很可能会因为等待时间过长而推出应用。广告预加载在此时…

美团后端Java实习一面面经

说一下AOP&#xff1f; 面向切面编程&#xff0c;通过预编译方式和运行期动态代理实现程序功能的统一维护的技术。可以减少程序中相同代码的编写&#xff0c;简化开发&#xff0c;使得接口更加专注于业务 相关概念 Aspect&#xff08;切面&#xff09;&#xff1a; Aspect 声…

【ES6语法学习】解构赋值

文章目录 引言一、什么是解构赋值1.1什么是解构赋值1.2 数组的解构赋值1.2.1 基本用法1.2.2 默认值1.2.3 剩余参数 1.3 对象的解构赋值1.3.1 基本用法1.3.2 默认值1.3.2 剩余参数 1.4 字符串的解构赋值1.5 函数参数的解构赋值 二、解构赋值的优势和应用场景2.1 代码简化和可读性…

并发程序设计--D2D3exec函数族和守护进程

exec 函数族 背景&#xff1a;fork创建进程之后&#xff0c;子进程和父进程执行相同的代码&#xff0c;但是在实际开发当中&#xff0c;我们希望父子进程执行不同的代码。 作用&#xff1a;执行指定的程序 #include <unistd.h> int execl(const char *path, const cha…

echarts中dataZoom拖拽不起效果

vue3项目中&#xff0c;echarts使用dataZoom进行区域拖动&#xff0c;拖动下图红色框&#xff0c;数据展示无变化拖动功能失效。 原因 vue3中使用了ref或者reactive等初始化图表的变量 //定义 let myChart ref<any>(null); //使用 myChart.value echarts.init(chartR…