一篇文章带你搞懂二分

article/2025/9/19 13:00:53

一篇文章教你搞懂二分

  • 二分
    • 整数二分
    • 实数域上二分
    • 二分查找
    • 二分答案

二分

到底什么是二分呢?二分二分就是一分为二。简单来说二分就是在有序序列中,通过不断的二分,进而不断地缩小范围去寻找满足我们条件的解。这只是对二分一个狭义上的理解,广义二分其实是如果有一个临界值使得临界值一边的数据满足一种性质,另一边满足另一种性质,即使不是有序的但也可以利用二分去寻找这个临界值。
在信息学竞赛中,二分题目主要分为二分查找二分答案,二分类型分为整数二分实数域上二分

整数二分

在写整数二分时,可以分为两种情况,一种将数轴分为[L,mid],[mid+1,R]两个部分,另一种将数轴分为[L,mid-1],[mid,R]两个部分,现在可能还不懂这是什么东西,我们接下来结合题目讲解。首先来看一下二分的基本模板吧

// 将区间分为[L,mid],[mid+1,R]
bool check(mid){//判断条件函数 
}
//终止条件是left==right 
while(left<right){int mid=(left+right)>>1;//这里使用右移运算主要是在负数时右移向下取整,除法向零取整if(check(mid)) right=mid;//判断如果mid这个值满足[L,mid]这个区间里面的的数的性质,则将r=mid,缩小范围 else left=mid+1; //否则另l=mid+1,+1的原因是mid不满足条件不能取 
}
cout<<left;// 将区间分为[L,mid-1],[mid,R]
while(left<right){int mid=(left+right+1)>>1;//这里一定要加1!原因稍后再讲 if(check(mid)) left=mid;//判断如果mid这个值满足[mid,R]这个区间里面的的数的性质,则将l=mid,缩小范围 else right=mid-1; //否则另r=mid-1,+1的原因是mid不满足条件不能取 
}
cout<<left;

看到上面的代码我相信你现在一定是一脸懵逼,没事我们接下来结合具体问题讲解

请看下面一道题,请在序列1 4 7 9 10中寻找大于等于8的第一个数

在做整数二分题目时,刚开始学习的比较困难的是选择上面的哪一个模板,我们先来分析一下这道题,这道题要求寻找第一个大于等于8的数,及以这个数为分界点,右边的都满足这个性质,左边的都不满足,很显然当mid>=8时,我们应该在下一次二分时让mid左移动,去寻找第一个>=8的数,所以下一次的查找区间应该是在[L,mid]中,很显然符合第一个情况。接下来我们结合图片了解一下每一步,首先先贴上代码便于食用

#include<iostream>
using namespace std;
int a[5]={1,4,7,9,10};
int right_bound(int x){int l=0;int r=5;while(l<r){int mid=(l+r)>>1;//跟(l+r)/2不同的是右移向下取整,除运算向零取整 if(a[mid]>=x) r=mid;//求的是闭区间 else l=mid+1;}return a[r];
}
int main(){cout<<right_bound(8);}

查找过程:
最初:
在这里插入图片描述
第一次查找:
计算出mid=(l+r)>>1=3(注意下标从0开始), 发现9比8大,为了寻找比8大的第一个数,就需要向左缩小范围,因为mid是满足条件的,所以另r=mid
在这里插入图片描述
在这里插入图片描述
第二次查找:
计算出mid=(l+r)>>1=1,显然4是小于8的就不满足条件,就需要向右缩小范围,因为mid不满足我们的条件,我们的需求是找到大于等于8的第一个数,所以l=mid+1。
在这里插入图片描述
在这里插入图片描述
第三次查找:
计算出mid=(l+r)>>1=2,由if(a[mid]>=x) r=mid; else l=mid+1,移动左指针,即改变l的值l=9
在这里插入图片描述
在这里插入图片描述
因为L==R,结束循环,输出答案

通过刚才的模拟,我相信大家对二分查找的过程肯定有大致的了解,但是在真实的做题中,往往困难的地方是对二分模板的选择方面,这个是值得大家思考的地方。

如果把题目改成小于等于8的第一个数呢?

显然这就要用到第二个模板了,过程就交给你们模拟了,直接贴代码

#include<iostream>
using namespace std;
int a[5]={1,4,7,9,10};
int left_bound(int x){int l=0;int r=5;while(l<r){int mid=(l+r+1)>>1;//注意这里要+1 if(a[mid]<=x) l=mid;//求的是闭区间 else r=mid-1;}return a[r];
}
int main(){cout<<left_bound(8);}

注意这里 mid=(l+r+1)>>1+1的主要原因是如果r-l=1,因为>>1是向下取整,所以mid=l,如果很不幸if(check()) l=mid;成立的话,你就会陷入无尽的死循环中。

总结:该模板保证最终答案处于闭区间[l,r]以内,循环以l=r结束,每次二分的中间值mid会归属于左半段与右半段二者之一,优点是几乎可以用于所有的二分题型,但缺点是需要分清楚两种情况,并根据实际情况选择相应的模板。

实数域上二分

相比较整数上的二分,实数域上的二分就简单很多了,实数域上二分需要注意的点是确定精度,这里有一个小技巧,如果题目上让保留k位小数,那么精度eps
就设置成1e^(-k-2)

//具体情况具体分析
double l=0,r=1000;//这里l与r的值一定要根据题目来设定,不能想当然的就从0开始
while(r-l>eps){double mid=(r-l)/2;if(check()) l=mid;else r=mid;
} 
cout<<l;

有的时候精度难以控制,也可以用设立二分次数的方法来控制精度

//具体情况具体分析
#include<iostream>
using namespace std;
int main(){double l=0,r=1000;for(int i=0;i<100;i++){double mid=(l+r)/2;if(check()) l=mid;else r=mid;}printf("%lf",l);
}

二分查找

二分查找也称折半查找,可以提高查找效率,上面的例题就是二分查找的一个实例,所以这里就不再赘述。重点在二分答案

二分答案

二分答案全称叫做二分答案转化为判定,这类问题通常用于答案的值域已经确定,并且很难从问题的本身去找到答案,这样就可以从答案值域入手,判定这个值符不符合题目要求,根据判定结果缩小范围从而找到最优值。

例题 : 数列分段

在这里插入图片描述
这道题我能想到的暴力做法是把所有的情况找出来,然后比较每段和的最大值从而找到每段和的最大值的最小值。这个思路想一想实现起来就比较麻烦,所以通过观察发现最大值的范围其实是固定的,它最大也不会超过整个序列的和,最小也不会小于这个序列中最大的那个数。那么我们就可以通过二分在这个范围进行查找,直到找到那个满足要求并且最小的那一个。
现在大致思路明白了,就要选择用哪一个模板,因为题目要求求最小值,也就是求刚好满足条件>=x的那个数,x为最小的和,很显然用的是[l,mid],[mid+1,r]这个区间的模板。如果mid导致分得的组数小于等于M了,就另r=mid,进一步缩小范围,因为mid越小分得的组数越多,否则另l=mid+1。

#include<iostream>
using namespace std;
const int N=1e5+10;
int n,m,a[N];
bool check(int x){//判断如果选择x作为每组的最大厚度,形成的组数,如果小于等于m就需要另最大厚度变小 ,反之变大 int t=1,size=x;for(int i=1;i<=n;i++){if(a[i]<=size) size=size-a[i];else size=x-a[i],t++;}return t<=m;
}
int main(){cin>>n>>m;int sum=0;int l=0,r;for(int i=1;i<=n;i++){cin>>a[i];l=max(l,a[i]);sum+=a[i];}r=sum;while(l<r){int mid=(l+r)>>1;if(check(mid)) r=mid;else l=mid+1;}cout<<l;}

从上面那道题中不难看出把查找转化为了判定可以大大提高了我们的效率也简化了问题,做这类题目主要是要写好check()函数,确定好值域范围


http://chatgpt.dhexx.cn/article/uH6ahfBl.shtml

相关文章

深入字节版atop: 线上系统的性能监控实践

背景 atop 是一款开源的单机性能监测工具&#xff0c;支持实时观测的同时、也支持读取历史文件排查问题。另外一个优点是除提供 CPU、MEM、DISK 等全局指标外&#xff0c;还提供进程、线程级别的各项指标监控数据。鉴于 atop 的这些优点&#xff0c;字节跳动基于社区的 atop 进…

atop备忘

atop 安装 sudo apt install atop atop 参数说明 监控界面字段说明 ATOP列&#xff1a;该列显示了主机名、信息采样日期和时间点 PRC列&#xff1a;该列显示进程整体运行情况 sys、usr字段分别指示进程在内核态和用户态的运行时间 #proc字段指示进程总数 #zombie字段指示僵…

atop linux,每天学一个 Linux 命令(117):atop

命令简介 atop 命令是一款监控 Linux 系统资源与进程的工具&#xff0c;非内部命令&#xff0c;需要安装。[rootcentos7 ~]# atop -bash: atop: command not found [rootcentos7 ~]# yum install atop -y #Debian && Ubuntu apt-get install atop #Fedora dnf install …

linux 系统性能 检测 命令 atop

atop 主要可以 监测 cpu,内存&#xff0c;硬盘&#xff0c;网络性能&#xff0c;以及 实时读写 日志。 基本用法 1.查看 atop , 实时刷新 按 a ,退出 按q 2.保存日志 atop -w log.txt 3.查看 输出日志 atop -r log.txt &#xff0c; 按 t 查看 下一个样本的性能数据 &a…

Atop使用场景

问题&#xff1a; 1、线上容器环境pod报错无法创建本地线程&#xff0c;如下图所示&#xff1a; 2、日志中出现报错信息 “fork&#xff1a;Cannot allocate memory”。如下图所示&#xff1a; 可能原因 1、内存不够 2、可能是进程数超限导致。系统内部的总进程数达到了 p…

atop工具使用

atop是linux系统下一款监控系统资源与进程的工具。atop以一定的频率记录系统的运行状态,通过它可以了解系统今生前世。atop采集系统资源「cpu、mem、disk、net」的使用情况及所有进程使用系统资源的情况,定期采集相关数据保存日志文件。可以通过atop.daily文件调整数据采集的…

atop安装和使用

atop就是一款用于监控Linux系统资源与进程的工具&#xff0c;它以一定的频率记录系统的运行状态&#xff0c;所采集的数据包含系统资源(CPU、内存、磁盘和网络)使用情况和进程运行情况&#xff0c;并能以日志文件的方式保存在磁盘中。atop是一款开源软件&#xff0c;目前最新版…

linux 之atop 系统监控工具

一、atop介绍 atop是一款用于监控Linux系统资源与进程的工具&#xff0c;它以一定的频率记录系统的运行状态&#xff0c;所采集的数据包含系统资源(CPU、内存、磁盘和网络)使用情况和进程运行情况&#xff0c;并能以日志文件的方式保存在磁盘中&#xff0c;服务器出现问题后&a…

Linux 使用 atop 监控工具

文章目录 应用场景操作步骤安装 atop配置并启动 atop编辑atop配置文件启动atop 分析atop停止atop 应用场景 atop 是一款用于监控 Linux 系统资源与进程的工具&#xff0c;以一定的频率记录系统的运行状态&#xff0c;采集系统资源&#xff08;CPU、内存、磁盘和网络&#xff0…

codeblocks中文包

kdevelop因为python 2.6.2 而不是要求的<2.6的缘故不可以显示出automake。 而删除&#xff12;.6的结果是&#xff11;&#xff13;&#xff12;个包同时要卸载&#xff0c;感觉其中不乏kde桌面的东东&#xff0c;遂放弃&#xff0c;转而投向codeblocks怀抱。 /usr/share/c…

codeblocks使用

原文来源&#xff1a;http://www.cnblogs.com/hackergodness/archive/2011/05/26/2059268.html 原手册下载&#xff1a; http://www.codeblocks.org/docs/manual_en.pdf 译者&#xff1a;JGood(http://blog.csdn.net/Jgood ) 译者言&#xff1a;工欲善其事&#xff0c;必先利其…

CodeBlocks安装及使用

Code::Blocks是一个开放源码的全功能的跨平台C/C集成开发环境&#xff0c;由纯碎的C语言开发完成&#xff0c;使用了著名的图形界面库wxWidgets。由于最近上机指导&#xff0c;学校ACM推荐同学们用的是这款软件&#xff0c;故而对其安装及使用进行一些记录。 一、Code::Blocks…

Code::Blocks介绍

软件类型&#xff1a;编程软件 软件性质&#xff1a;免费软件 操作系统&#xff1a;veket 应用平台&#xff1a;veket全系列 网站链接&#xff1a;http://www.codeblocks.org Code::Blocks 是一个开放源码的全功能的跨平台C/C集成开发环境.   相比于基于Delphi的Dev-C共享 CI…

Codeblock汉化教程

#Codeblock汉化教程 我猜许多人和我一样每次拿到一个IDE都不太懂上边的英文是什么意思&#xff0c;而且现在大多数的IDE都没有汉化用起来感觉很麻烦&#xff0c;可能是我用的太少了。最近在练习一些C的东西觉得Codeblock这个IDE用起来比较方便&#xff0c;但是满篇的英文看的我…

codeblock图形界面编程(十)文件操作

目录 codeblock图形界面编程&#xff08;十&#xff09;文件操作C语言的文件管理文件指针文件打开 文件关闭文件读文件写 图形界面的文件操作管理配置libcomdlg32.a库系统功能的实现 codeblock图形界面编程&#xff08;十&#xff09;文件操作 打开我们的计算机&#xff0c;无…

codeblocks应用之debug .

一个偶然的机会&#xff0c;我发现了codeblocks这款IDE&#xff0c;因为它主要用于开发c/c&#xff0c;所以没有visual studio那么臃肿&#xff0c;感觉比较快捷&#xff0c;好用。但是其资料多为英文&#xff0c;本着利人利己的初衷&#xff0c;我决定挑选一些开发中必须使用的…

codeblock报错解决及正确安装

文章目录 前言报错解决原因一原因二 正确安装 前言 文章同步于我的个人博客https://quan9i.github.io/c/#more&#xff0c;欢迎大家访问&#xff01; 最近在重新使用codeblock时发现了部分问题&#xff0c;总结如下 报错解决 在运行时出现如下报错 "HelloWorld - Debu…

codeblocks 使用汇总

享受Code::Blocks编辑快感的几个关键 原文地址&#xff1a;http://blog.csdn.net/Utensil/archive/2008/12/24/3593502.aspx 感谢Loaden的补充。此文是对帖子http://wxforum.shadonet.com/viewtopic.php?t22128 的总结和整理&#xff0c;按个人喜好做了取舍和重新排序。 说明…

CodeBlocks 的下载安装

一、下载 1.在浏览器上输入CodeBlocks或者输入网址https://www.codeblocks.org/&#xff0c;进入CodeBlocks官网 2.点击Downloads&#xff0c;进入Downloads界面 3.进入Downloads页面&#xff0c;点击Download the binary release&#xff08;二进制版&#xff09; 4.选择下…

Code::Blocks的使用教程

四年没有认真地写过C了&#xff0c;决定从今天开始&#xff0c;从codeblocks开始&#xff01; 打开软件界面&#xff0c;点击“创建新项目” 选择“console application”&#xff0c;然后点“出发” 点击“下一步” 选择“c”&#xff0c;点击“下一步” 输入项目标题 选“…