洛谷 P1873 砍树 (二分 简单)

【二分答案】是分治的一种,这类问题很经典,接下来几篇文章会关于二分答案相关的文章,希望同学们可以完成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)?

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue知识总结-上

VUE初识 Vue是一套用于构建用户界面的渐进式(由只需要轻量小巧的核心库构建的简单应用逐渐扩展为可以引入各式各样的Vue组件构建的复杂应用)JavaScript框架 Vue需掌握的内容&#xff1a;Vue基础、Vue-cli、vue-router、vuex、element-ui、vue3 Vue特点 采用组件化模式、提高代…

AIGC初探:提示工程 Prompt Engineering

简介 提升工程是什么 提示工程&#xff08;Prompt Engineering&#xff09;是人工智能领域中的一个概念&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;领域中。它是一种通过设计和优化输入提示来提高AI模型表现的方法。 对于基于转换器的大型语言模型&#x…

金智维KRPA问题集锦

KRPA问题集锦 1、打开浏览器错误 &#xff08;1&#xff09;浏览器插件问题&#xff0c;需要正确安装ChromePlug插件&#xff0c; &#xff08;2&#xff09;windows系统下需要正确配置chrome.exe运行环境变量

代码随想录算法训练营第十五天| 二叉树 513. 找树左下角的值 112. 路径总和 106.从中序与后序遍历序列构造二叉树

513. 找树左下角的值 层序遍历 本题用层序遍历可以直接秒了&#xff0c;直接提取每一层中最左边的元素&#xff08;i0&#xff09;&#xff0c;然后保存到最后一层即可。 class Solution { public:int findBottomLeftValue(TreeNode* root) {queue<TreeNode*> que;int…

Apache Camel笔记

Apache Camel笔记 1. Apache Camel概念 Apache Camel是一个轻量级的应用集成开发框架&#xff0c;专注于简化集成应用的开发。它基于Enterprise Integration Patterns&#xff08;企业集成模式&#xff0c;简称EIP&#xff09;的设计理念&#xff0c;提供了灵活的路由和中介机制…

【愚公系列】2023年12月 HarmonyOS教学课程 015-ArkUI组件(Radio)

&#x1f3c6; 作者简介&#xff0c;愚公搬代码 &#x1f3c6;《头衔》&#xff1a;华为云特约编辑&#xff0c;华为云云享专家&#xff0c;华为开发者专家&#xff0c;华为产品云测专家&#xff0c;CSDN博客专家&#xff0c;CSDN商业化专家&#xff0c;阿里云专家博主&#xf…

docker容器添加新的端口映射

通常在运行容器时&#xff0c;我们都会通过参数 -p来指定宿主机和容器端口的映射&#xff0c;例如 docker run -it -d --restart always --name [指定容器名] -p 8899:8080 [指定镜像名]上述命令将容器内的8080端口映射到宿主机的8899端口。 参数说明 -d 表示后台运行容器 -t…

【springboot+vue项目(十一)】springboot整合EasyExcel

EasyExcel是阿里巴巴开源的一个Java库&#xff0c;用于操作Excel文件。它提供了简单易用的API&#xff0c;可以读取、写入和转换Excel文件&#xff0c;支持大量数据的导入和导出操作。 一、添加依赖&#xff08;版本3.2&#xff09; <!--easyexcel操作excel--> <depe…

Unity 点击对话系统(含Demo)

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

014、枚举与模式匹配

枚举类型&#xff0c;通常也被简称为枚举&#xff0c;它允许我们列举所有可能的值来定义一个类型。在本篇文章中&#xff0c;我们首先会定义并使用一个枚举&#xff0c;以向你展示枚举是如何连同数据来一起编码信息的。 接着&#xff0c;我们会讨论一个特别有用的枚举&#xff…

figma导入psd实战笔记

最近发现figma特别好用 并且插件生态特别庞大 如 将设计图转成vue react react-native 项目 flutter 项目 最重要的是 可以集成vscode 插件使用 使用蓝湖久了 感觉蓝湖 有写繁琐 同事扩展功能有限 Figma: The Collaborative Interface Design ToolFigma is the leading collabo…

上帝视角俯视工厂设计模式

引言 本篇聊聊设计模式中的简单工厂、工厂方法、抽象工厂设计模式&#xff0c;争取在看完这篇后不会再傻傻分不清以及能够应用在实际项目中 背景 以一个咱们都熟悉的场景举个例子&#xff0c;我们平时都会戴口罩&#xff0c;用来过滤一些普通病毒&#xff0c;大致的设计如下…

电脑记事本怎么打开?电脑记事本打开方法

在日常工作中&#xff0c;许多上班族都习惯于使用电脑记事本记录重要事项、灵感想法或临时任务。电脑记事本轻便、简洁&#xff0c;能够为我们提供便捷的记事体验。那么电脑记事本怎么打开呢&#xff1f;电脑记事本打开方法是什么呢&#xff1f;在Windows电脑上&#xff0c;我们…

手把手教你用Python打造一个语音合成系统

目录 引言 一、了解语音合成技术 1.1 什么是语音合成技术 1.2 语音合成技术的分类 二、准备所需工具和库 2.1 Python编程语言 2.2 TensorFlow深度学习框架 2.3 WaveNet模型 三、搭建语音合成系统 3.1 数据准备 3.2 数据预处理 3.3 构建WaveNet模型 3.4 训练WaveNe…

京东年度数据报告-2023全年度净水器十大热门品牌销量榜单

近年来&#xff0c;随着科技的不断发展和应用&#xff0c;净水器的技术得到持续创新和提高&#xff0c;产品品质和使用效果不断优化&#xff0c;这也进一步提升了净水器的市场竞争力&#xff0c;2023年&#xff0c;净水器市场的销售成绩呈现增长。 根据鲸参谋平台的数据显示&a…

大语言模型占显存的计算和优化

可以优化的地方&#xff1a; per_device_train_batch_size&#xff08;相当于batch size&#xff0c;越小显存占的越小&#xff09; gradient_accumulation_steps&#xff08;per_device_train_batch_size*gradient_accumulation_steps计算梯度的数据数&#xff09; gradien…

【CSS】设置0.5px的边框宽度

直接写border: 0.5px solid red; 这样在移动端可能会出现问题&#xff0c;下面说下解决办法&#xff1a; 直接上代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-C…

1.4 day4 IO进程线程

使用两个子进程进行文件拷贝&#xff0c;父进程进行资源回收 #include <myhead.h> int main(int argc, const char *argv[]) {//创建一个文件描述符并以只读的方式打开int fd-1;if((fdopen("./test.bmp",O_RDONLY))-1){perror("open error");return…

2023年度全球重大关基安全事件 TOP 10 | FreeBuf 年度盘点

2023年&#xff0c;针对关键信息基础设施的网络攻击已经演变成为了一个全球性的问题&#xff0c;无论是中、美、俄等国际大国&#xff0c;还是诸多小国/地区&#xff0c;无论是经济发达还是落后&#xff0c;都无法保证绝对免疫关键基础设施的攻击。为了保障国家安全和社会稳定&…

Python Selenium如何下载网页中的图片到本地?(Base64编码的图片下载)

前言&#xff1a; 在网页上&#xff0c;图片有时会以Base64编码的形式嵌入在HTML中&#xff0c;而不是作为单独的文件提供。这种方式的优点是可以减少HTTP请求的数量&#xff0c;因为图片数据直接包含在HTML中&#xff0c;不需要额外的请求来获取图片文件。这对于小图片…