『学习笔记』二分算法

news/2025/1/26 14:07:40/文章来源:https://www.cnblogs.com/2026zhaoyl/p/18306533

今天记录二分知识点。

二分是一个简单清晰,实用性强的算法。

也是本人最喜欢的算法之一。

先给出二分模板吧!

	int l = 1, r = n;//初始值,根据情况而定while (l + 1 < r) {int mid = (l + r) >> 1;if (check(mid)) l = mid;// check函数判断左半部分是否不符合,更新 lelse r = mid;// 否则更改 r}

Part one: 二分搜索

二分是一种高效的查找方法,‌它会将搜索范围一分为二,‌减小搜索范围,‌直到找到目标或确定目标不存在。‌一般可以将时间复杂度从 \(O(n)\) 优化到 \(O(\log_2 n)\)。‌

但是,二分有个前提要求,就是应具有单调性,比如单调不递减(升序)序列。

\(edg.\) 在一个升序序列 \(s\) 中找到一个指定值 \(x\)。令 $n = |s| $, \(n \leq 10^6\)

大家想到的第一种方法应该是遍历整个序列找 \(x\) 吧。这种方法的时间复杂度为 \(O(n)\),在某些时候并不足够优秀,可能导致 \(TLE\)

这时,大名鼎鼎的二分就能发挥其作用了。

先看一段代码:

	scanf("%d", &x); // 查找的数字  stable_sort(a + 1, a + n + 1);// 排序,使序列具有单调性,才能二分  int l = 1, r = n;while (l + 1 < r) {int mid = (l + r) >> 1;if (a[mid] <= x) l = mid;else r = mid;}pos = l;printf("%d", pos);

二分的第一步就是确定查找的范围,即 \(l\)\(r\) 的初始值。

在序列中二分时,\(l\) 一般是 \(1\)\(r\) 一般是序列最后一位的下标。

二分时,首先找出中间值,即 mid = (l + r) >> 1,等价于 mid = (l + r) / 2

然后,我们需要更新左右端点的值。

\(mid\) 左边的数已经不满足条件,就可以把 \(mid\) 左边舍弃,将左端点( \(l\) )更新为 \(mid\)

否则,缩小范围,既然左边满足条件,我们只需关注左边的部分,将右端点( \(r\) )更新为 \(mid\)

此时,区间就缩小到 \((l, mid)\)\((mid, r)\)了。

之后不断如此操作,就能将时间复杂度大大减少。

看模板,此时的 \(check(mid)\) 函数为:a[mid] <= x

Part two:二分答案

什么是二分答案呢?顾名思义,我们二分的不再是坐标,而是此题的答案。

同样重要的是单调性!答案具有单调性,才能使用二分大法。

再次看到二分模板。

int l = 1, r = n;
while (l + 1 < r) {int mid = (l + r) >> 1;if (check(mid)) l = mid;else r = mid;
}

此时,二分中的 \(check\) 函数便是判断 \(mid\) 是否满足要求,然后与二分查找一样,减短 \(l\)\(r\) 的范围。

是不是很 easy 呢?光说不练假本事,上道例题。

luogu P2440

题目大意人话

使 \(\sum_{i = 1} ^ {n}\lfloor \frac{a_i}{l} \rfloor = k\)\(l\) 的最大值,即 \(l_\max\)

不难发现,随着 \(l\) 的不断增大,总和在不断减少。这就是我们梦寐以求的单调性!接下来,我们就可以快乐地写二分了。

想想 check 函数怎么写。

没错,记录当 \(l = x\) 时能砍下的总段数 \(sum\),判断是否 \(sum \geq k\) 即可。

如此代码:

inline bool check(int x) {int ret = 0;for (int i = 1; i <= n; ++i)ret += a[i] / x;return ret >= k;
}

如果满足,由于求满足条件的最大值,\(mid\) 左边就没有价值去搜索了,将目光转向右边,即将左端点更新为 \(mid\)

否则,同理,将右端点更新为 \(mid\)

最后答案便储存在 \(l\) 里了。

你的第一道二分题就 \(Accepted\) 啦。

image

#include <bits/stdc++.h>
#define ll long long
#define pii pair <int, int>
using namespace std;
const int N = 1e5 + 10;
int a[N], n, k;
inline bool check(int x) {int ret = 0;for (int i = 1; i <= n; ++i)ret += a[i] / x;return ret >= k;
}
int main() {scanf("%d%d", &n, &k);int l = 0, r = 1;//注意有无解情况,l的初始值为0。for (int i = 1; i <= n; ++i) {scanf("%d", &a[i]);r = max(r, a[i]);}while (l + 1 < r) {int mid = (l + r) >> 1;if (check(mid)) l = mid;else r = mid;}printf("%d", l);return 0;
}

这里有一个题单,同学们一起进步吧~

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回家之难难于蜀道难

回家难 之难于蜀道难 (仿写李白蜀道难)噫吁嚱,困乎难乎,回家之途,难于上班路。 盘古及女娲,开天辟地捏人烟,尓来文明已万年,难解归家争吵事。 游子无钱难上路,漂留外地护空城。 千思万想定下来,踏上归途望团年。 上有爸妈在老家,下有孩童八九岁。 列车无票不得行,驱…

MAC|Edge——下载视频

解码错误解码错误指的是当前音/视频帧与浏览器不兼容,可以尝试以下方式:1.chrome/edge 浏览器打开chrome://flags,搜索 Hardware-accelerated video decode,选择 disabled2.如果解码错误仍然存在,请对视频进行转码处理,以修复问题帧3.firefox浏览器请打开about:support,…

stdio.h的缓冲机制解析

在C语言中,由于stdio.h中的缓冲机制,printf的输出常令人感到迷惑。本文将介绍其缓冲机制的具体细节1. 令人迷惑的printf() 在C语言中,由于stdio.h中的缓冲机制,printf的输出通常会受到缓冲区的影响。 这种影响可能非常微妙,并常常令人疑惑,比如我们来看下面这段代码 #inc…

【新能源行业】新能源汽车电子驻车制动系统(EPB)谁在做?

长期以来,汽车的动力系统一直是人们所关注的焦点,然而,汽车制动系统在背后默默支撑起整个汽车安全与稳定。其重要性丝毫不亚于动力系统。行车上路,安全第一。在每一次的启程与停驻之间,唯有制动系统作为坚实保障,才能让每一次出行都安心无虞。一、制动系统分类与组成 目前…

如何从内存中提取shellcode

恶意程序有时会直接在内存中运行shellcode 。在这篇文章中,我将向你展示如何从内存中获取shellcode。 shellcode在内存中的位置 在内存中分配shellcode的常用方法是使用VirtualAlloc来分配具有所需权~限的内存。然后恶意软件使用RtlMoveMemory将shellcode写入分配的空间。然后…

施耐德UNITY中使用ST 语言计算日均值

以前做过练习,在unity中计算分钟均值和小时均值,做成自定义功能块。今天在家打算按照同样的思路,试着做一下日均值。 第一次打算建立一个三维数组PV_DAY[0..23,0..59,0..59],每秒存放一个数据,编译的时候提示数组太大。 第二次尝试建立24个数组,每个数组存放一个小时内36…

【转载】rpm 和 yum 软件包的应用

本节所讲内容:8.1 使用rpm命令-安装-查看-卸载-rpm软件包8.2 yum管理软件包8.3 CentOS8中使用DNF管理软件包8.4 实战tar源码包管理-源码包安装方法8.1 软件包的管理软件包的类型rpm二进制包------》已经使用GCC编译后的(二进制已经可以被操作系统直接执行了)tar源码包-----》…

[Redis] Redis (5) 多核多线程架构

序 引言Redis 作为一款高性能的内存数据库,以其简单的设计和单线程模型(潜台词:单核单线程)广受欢迎。 然而,随着用户需求和数据规模的增长,单线程的架构逐渐成为 Redis 性能的瓶颈。 近年来,Redis 开始引入部分多线程机制,以提高并发性能,特别是在处理网络 I/O 和数据持…

Python并行计算与高性能计算7迎接并行计算革命

在本章中,我们将介绍我们在前几章中看到的并行编程的实际方面。随着并行计算概念的扩展,它不仅包括并行编程及其相关方面,还包括能够管理并专门设计的基础设施。超级计算机通常被定义为由许多 CPU 和 GPU 组成的高性能系统,其中应用了并行计算和高性能计算 (HPC) 方法。本章…

人脸识别和神经风格转换

人脸识别和神经风格转换 人脸识别人脸验证(Verification):验证输入图像是否属于某个特定身份,属于一对一问题。 人脸识别(Recognition):一对多问题,从大量数据中找到匹配的人脸。 在很多人脸识别应用中,系统需要通过单一样本识别某人,而非多个样本,这就属于 One-shot Le…

dubbo 2.7.2 启动报错【Unsupported generic type false】排查

💖1.问题现象 dubbo服务启动时抛出异常Unsupported generic type false,但不影响服务正常发布。 Caused by: java.lang.IllegalArgumentException: Unsupported generic type false📖2. 版本信息 SpringBoot 2.1.3 + Dubbo 2.7.2 👉3. 问题根因 项目中使用了Spring Boot…

[Redis] Redis (5) 多核多线程模型

序 引言Redis 作为一款高性能的内存数据库,以其简单的设计和单线程模型(潜台词:单核单线程)广受欢迎。 然而,随着用户需求和数据规模的增长,单线程的架构逐渐成为 Redis 性能的瓶颈。 近年来,Redis 开始引入部分多线程机制,以提高并发性能,特别是在处理网络 I/O 和数据持…