【C++算法】二分算法、二分模板详解,四道例题带详细注释

文章目录

  • @[toc]
    • 1)整数二分
    • 2)解二分题步骤
      • AcWing 789.数的范围
      • 洛谷 P1873.EKO/砍树
      • 洛谷 P1678.烦恼的高考志愿
    • 2)浮点二分
      • AcWing 790. 数的三次方根

1)整数二分

  • 有单调性的题目一定可以二分,但是用二分做的题目不一定拥有单调性。
  • 二分的本质不是单调性,二分的本质是边界,两套模板如下:
  • 套模板时经常容易出现边界问题,那么什么时候选择哪套模板?听了y总的思路后,结合我自己的想法,接下来解析两套模板:
  • 首先想 c h e c k check check函数,再想如何更新区间,如果是 l = m i d l=mid l=mid,那么补上 + 1 +1 +1,如果是 r = m i d r=mid r=mid,那么不需要补上 + 1 +1 +1
  • ① 如果答案在右边,比如:找最大值,或者最后一个出现的位置;那么 l = m i d l=mid l=mid,那么对立面就是 r = m i d − 1 r=mid-1 r=mid1 m i d = l + r + 1 > > 1 mid= l+r+1>>1 mid=l+r+1>>1
  • ② 如果答案在左边,比如:找最小值,或者第一个出现的位置;那么$ r=mid$,那么对立面就是 l = m i d + 1 l=mid+1 l=mid+1 m i d = l + r > > 1 mid= l+r>>1 mid=l+r>>1
  • 对于第一种情况①,为什么要+1?可以想象一下,如果已经找到答案, m i d = l = r mid=l=r mid=l=r,那么 m i d = l + r > > 1 mid=l+r>>1 mid=l+r>>1就还是 [ l , r ] [l,r] [l,r],又因为包含答案,所以再次更新结果还是 [ l , r ] [l,r] [l,r],就会陷入死循环,也就是我们说的边界问题
  • 注意:二分一定是有解的,不可能无解,无解永远是题目的无解而不是二分的无解。
// 答案在左边,能取到答案
int bsearch_1(int l,int r) {
	while(l<r) {
		int mid=l+r>>1;
		if(check(mid))
			r=mid; // [l,mid]
		else
			l=mid+1; // [mid+1,r]
	}
	return l;
}

// 答案在右边,能取到答案
int bsearch_2(int l,int r) {
	while(l<r) {
        // 如何理解这个+1,见上述解析
		int mid=l+r+1>>1;
		if(check(mid))
			l=mid; // [mid,r]
		else
			r=mid-1; // [l,mid-1]
	}
	return l;
} 

2)解二分题步骤

  • 题目中出现求最值,首先想到二分/贪心/动态规划等算法

  • 题目具有单调性,则可以考虑用二分求解

  • 分析使用哪个模板

    1. 第一次出现,求第一个大于等于/大于/小于/小于等于某个数的数,求解最小值,说明答案在左边,用第一个模板

    2. 最后一次出现,最后一个大于等于/大于/小于/小于等某个数的数,求解最大值,说明答案在右边,用第二个模板

  • 写check函数

AcWing 789.数的范围

题目链接:789. 数的范围 - AcWing题库

在这里插入图片描述

#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;

// 题目描述: 
// 找数字的左端点:大于等于x的第一个位置,q[mid]>=x,更新:R=mid,L=mid+1,当l=r时,若q[r]!=x,说明第一个大于等于x的位置不是x,则找不到
// 找数字的右端点:大于等于x的最后一个位置,q[mid]<=x,更新:L=mid,R=mid-1,当l=r时,若q[r]!=x,说明最后一个大于等于x

const int N=1e5+10;
int n,m;
int q[N];

int main() {
	cin>>n>>m;
	for(int i=0;i<n;i++) cin>>q[i];
	// m次询问
	while(m--) {
		int x;
		cin>>x;
		// 二分x的左端点
		int l=0,r=n-1; // 区间范围
		while(l<r) {
			int mid=l+r>>1;
			if(q[mid]>=x) r=mid;
			else l=mid+1;
		}
		if(q[r]==x) {
			// 存在左端点,输出
			cout<<r<<' ';
			
			// 继续找右端点,左端点继续从上一次搜索的终点开始找
			r=n-1;
			while(l<r) {
				int mid=l+r+1>>1;
				if(q[mid]<=x) l=mid;
				else r=mid-1;
			}
			cout<<r<<endl; // 输出一组解
		} else {
			cout<<"-1 -1"<<endl;	
		}
	}
	return 0;
}

洛谷 P1873.EKO/砍树

题目链接:[P1873 COCI 2011/2012 #5] EKO / 砍树 - 洛谷

#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;

// 解题思路: 

const ll N=1e6+10;
ll n,m; // n:树的数量,m:要的木材总长度
ll a[N]; // 存储树的高度

// 如果有木头有这么多,就返回true
bool check(ll mid) {
	ll cnt=0;
	for(ll i=1;i<=n;i++) {
		if(a[i]-mid>0) {
			cnt+=a[i]-mid;
		}	
	}
	if(cnt>=m) return true;
	else return false;
}

int main() {
	ll mmax=INT_MIN;
	cin>>n>>m;
	for(ll i=1;i<=n;i++) {
		scanf("%d",&a[i]);
		mmax=max(mmax,a[i]);
	}
	ll l=0; // 锯子最小高度为0,全切
	ll r=mmax; // 最高切完最大的这棵树,一棵都不切
	// 要找最大值,那么答案在右边,所以压缩左边界
	while(l<r) {
		ll mid=l+r+1>>1;
		if(check(mid)) {
			l=mid;
		} else {
			r=mid-1;
		}
	}
	cout<<l<<endl;
	return 0;
}

洛谷 P1678.烦恼的高考志愿

题目链接:P1678 烦恼的高考志愿 - 洛谷

#include<bits/stdc++.h>
#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

// 解题思路: 开ll不然过不了

const ll N=1e5+5;
ll n,m;
ll a[N]; // 存储学校的分数线
ll b[N]; // 存储每个同学的估分

int main() {
	cin>>n>>m;
	// n个学校,m个同学
	for(ll i=1;i<=n;i++) {
		scanf("%lld",&a[i]);	
	}
	for(ll i=1;i<=m;i++) {
		scanf("%lld",&b[i]);
	}
	sort(a+1,a+1+n);
	ll cnt=0;
	// 遍历所有同学
	for(ll i=1;i<=m;i++) {
		// 卫语言风格
		// 比最小值还小,跳过
		if(b[i]<=a[1]) {
			cnt+=abs(b[i]-a[1]);
			continue;
		}
		else if(b[i]>=a[n]) {
			cnt+=abs(b[i]-a[n]);
			continue;
		}
		ll l=1,r=n; // 边界是[1,n]
		while(l<r) {
			ll mid=l+r>>1;
			// 注意找第一个是答案在左边的问题,所以要压缩右边界
			// 找第一个大于等于b[i]的第一个学校的分数线a[l]
			// 那么最后一个小于b[i]的元素的下标就应该是a[l-1]
			if(a[mid]>=b[i])
				r=mid;
			else
				l=mid+1;
		}
		// 取二者之中的最小值
		cnt+=min(abs(a[l]-b[i]),abs(a[l-1]-b[i]));
	}
	cout<<cnt;
	return 0;
}

2)浮点二分

AcWing 790. 数的三次方根

题目链接:790. 数的三次方根 - AcWing题库

  • 对于开二次方根,因为开出来一定是正数,所以可以设置 l = 0 l=0 l=0 r = x r=x r=x,但是三次方根可能有负数,不能单纯的取 l = − x l=-x l=x r = x r=x r=x,这样的话输入的 x x x是正数,范围是 [ − x , x ] [-x,x] [x,x],输入的数是负数,范围是 [ x , − x ] [x,-x] [x,x]就会出大问题。
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
int main() {
	double x;
	cin>>x;
	// 因为是开三次方根,所以要考虑负数的情况
    // 注意
	double l=-100000,r=100000;
	// 保留6位小数就1e-8(基于经验),同理保留4位就1e-6
	while(r-l>1e-8) {
		double mid=(l+r)/2;
		if(mid*mid*mid>=x)
			r=mid;
		else
			l=mid;
	}
	cout<<setprecision(6)<<fixed<<l<<endl;
	return 0;
}

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

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

相关文章

【物联网开源平台】tingsboard二次开发环境搭建+编译

文章目录 一&#xff0c;需要准备的环境二&#xff0c;获取tingsboard源码1.git拉取源码2.下载源码压缩包 三.新建仓库存放依赖文件四&#xff0c;编译五&#xff0c;遇到的错误 提示&#xff1a; 1.这篇只要准备两个环境&#xff0c;方法更简单&#xff01; 2.基于tingsboard …

动态路由协议——OSPF

目录 一.OSPF来源 二.OSPF术语 1.area id——区域的划分 2.cost——路径开销值 3.route id 4.LSDB表 5.邻居表 6.OSPF路由表 三.OSPF工作过程 1.交互hello报文建立邻居关系 2.选举主从 3.交互LSDB摘要信息 4.LSR,LSU,LSACK同步LSDB表项 5.各自计算路由 四.OSPF交…

【Linux命令】查看内存占用情况(mem, swap)

1. 方法1&#xff08;top&#xff09; # top2.方法2&#xff08;free&#xff09; # free -h3. 方法3&#xff08;swapon&#xff09; # swapon -s

Spring Boot1

SpringBoot概述 Spring Boot是Spring提供的一个子项目&#xff0c;用于快速构建Spring应用程序 SpringBoot特性 起步依赖 本质上就是一个Maven坐标&#xff0c;整合了完成一个功能所需要的所有坐标 自动配置 遵循约定大于配置的原则&#xff0c;再boot程序启动后&#xff0…

【MySQL】深入解析事务与MVCC

文章目录 1、事务四大特性1.1、原子性1.2、一致性1.3、隔离性1.4、持久性 2、并发事务带来问题2.1、脏读2.2、不可重复读2.3、幻读 3、事务隔离级别3.1、读未提交3.2、读已提交3.3、可重复读3.4、串行化 4、MVCC4.1、InnoDB隐藏字段4.2、undo log版本链4.3、ReadView4.4、MVCC工…

fiddler过滤器使用,隐藏图片、js、css请求

如果抓包过程中不想查看图片、js、css请求&#xff0c;或者只想抓某个ip或者某个网页下的请求&#xff0c;可以在过滤器中设置。 &#xff08;1&#xff09;没有开启过滤器 可以看出所有的请求都会抓取&#xff0c;cs、js、图片请求都有 &#xff08;2&#xff09;开启过滤器 …

波奇学Linux:网络套接字

domain:ipv4 还是ipv6 type:面向字节流还是... 虚拟机 云服务器禁止直接bind公网ip 服务器可以有多个ip&#xff0c;如果只绑定一个ip&#xff0c;只能收到来自一个ip的信息 任意地址绑定 关于port的问题 [0,1024]&#xff1a;系统内定的端口号&#xff0c;一般要用固定的应…

基于SpringBoot+MyBatis框架的智慧生活商城系统的设计与实现(源码+LW+部署+讲解)

目录 前言 需求分析 可行性分析 技术实现 后端框架&#xff1a;Spring Boot 持久层框架&#xff1a;MyBatis 前端框架&#xff1a;Vue.js 数据库&#xff1a;MySQL 功能介绍 前台功能拓展 商品详情单管理 个人中心 秒杀活动 推荐系统 评论与评分系统 后台功能拓…

基于Matlab的眼底图像血管分割,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

光速论文能用吗 #媒体#知识分享#学习方法

光速论文是一个非常有效的论文写作、查重降重工具&#xff0c;它的使用非常简单方便&#xff0c;而且功能强大&#xff0c;是每个写作者必备的利器。 首先&#xff0c;光速论文具有强大的查重降重功能&#xff0c;能够快速检测论文中的抄袭部分&#xff0c;帮助作者避免不必要的…

2021年12月更新千言万语汇聚成一张图

今年的双十二几乎不复存在。 11月11日之后&#xff0c;有读者问我要不要等双十二。 现在看来&#xff0c;房东已经没有多余的粮食了&#xff0c;互联网的冬天比以前来得早得多。 进入12月份&#xff0c;公司同事和项目组的合伙人最近讨论的不再是年终奖&#xff0c;而是项目能…

解决mysql问题: this is incompatible with sql_mode=only_full_group_by

今天在部署一趟测试环境的服务&#xff0c;各种配置文件都配好了&#xff0c;启动服务后台报错&#xff0c;解决后记录一下&#xff0c;小伙伴们也可以看看&#xff01; ### Cause: java.sql.SQLSyntaxErrorException: Expression #1 of SELECT list is not in GROUP BY clause…

004——内存映射(基于鸿蒙和I.MAX6ULL)

目录 一、 ARM架构内存映射模型 1.1 页表项 1.2 一级页表映射过程 1.3 二级页表映射过程 1.4 cache 和 buffer 二、 鸿蒙内存映射代码学习 三、 为板子编写内存映射代码 3.1 内存地址范围 3.2 设备地址范围 一、 ARM架构内存映射模型 &#xff08;以前我以为页表机制…

力扣● 84.柱状图中最大的矩形

84.柱状图中最大的矩形 需要找到元素i的上一个更小的元素leftmin和下一个更小的元素rightmin&#xff0c;这样leftmin和rightmin之间的元素都比当前元素i更大&#xff0c;那么矩形的宽就是中间的这些元素&#xff1a;可以从leftmin1延伸到rightmin-1&#xff0c;长即为height[i…

阿里云轻量应用服务器和云服务器ECS有什么区别?

阿里云服务器ECS和轻量应用服务器有什么区别&#xff1f;轻量和ECS优缺点对比&#xff0c;云服务器ECS是明星级云产品&#xff0c;适合企业专业级的使用场景&#xff0c;轻量应用服务器是在ECS的基础上推出的轻量级云服务器&#xff0c;适合个人开发者单机应用访问量不高的网站…

dash 初体验(拔草)

Dash简介 Dash 是一个高效简洁的 Python 框架&#xff0c;建立在 Flask、Poltly.js 以及 React.js 的基础上&#xff0c;设计之初是为了帮助前端知识匮乏的数据分析人员&#xff0c;以纯 Python 编程的方式快速开发出交互式的数据可视化 web 应用。 搭建环境 在学习 Dash 的…

算法之美:数据结构之二叉树

平时写业务代码的时候很少写对应的算法&#xff0c;因为很少会在内存中存储大量数据&#xff0c;在需要比较大量数据的查找时&#xff0c;多会依赖的中间件&#xff0c;而中间件底层就应用了很多不同算法&#xff0c;尤其是树结构的查找存储算法&#xff0c;二分查找算法在树里…

把 Taro 项目作为一个完整分包,Taro项目里分包的样式丢失

现象&#xff1a; 当我们把 Taro 项目作为原生微信小程序一个完整分包时&#xff0c;Taro项目里分包的样式丢失&#xff0c;示意图如下&#xff1a; 原因&#xff1a; 在node_modules/tarojs/plugin-indie/dist/index.js文件里&#xff0c;限制了只有pages目录下会被引入app.w…

C# WPF编程-事件

C# WPF编程-路由事件 路由事件概要路由事件的三种方式 WPF事件WPF最重要的5类事件&#xff1a;生命周期事件 鼠标事件键盘事件多点触控输入原始触控 路由事件概要 路由事件是具有更强传播能力的事件&#xff0c;它们可在元素树中向上冒泡和向下隧道传播&#xff0c;并沿着传播…

稀碎从零算法笔记Day21-LeetCode:单词规律

题型&#xff1a;哈希表、字符串 链接&#xff1a;290. 单词规律 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&am…