《算法竞赛进阶指南》学习总结 二分与三分

首先......我是一个很菜很菜的萌新,所以这篇文章写得很详细,有很多我自己的口水话方便我理解,请各位谨慎食用qwq
以前在网上找过很多介绍二分的博客,但都感觉对萌新不太友好,反正我当时连跳石头都没看懂,所以决定自己写一篇!其中有我的想法,也借鉴了书里的很多内容,感谢lyd。

二分答案,顾名思义,就是对我们所需要的答案进行二分,对我们要求的值进行二分。
二分的基础用法是在单调序列或者单调函数当中查找,当答案具有单调性,我们就可以采用二分来计算,当然还有三分,在后面我会详细讲到

整数集合上的二分

在单调递增序列a中查找>=x的数当中最小的一个

while(l<r)
{
int mid=(l+r)>>1;
if(a[mid]>=x) r=mid; //普适模板:if(check()) r=mid;else l=mid+1;,下同。
else l=mid+1;
}
return a[l];

在单调递增序列a中查找<=x的数当中最大的一个

while(l<r)
{
int mid=(l+r+1)>>1;
if(a[mid]<=x) l=mid;
else r=mid-1;
}
return a[l];

根据以上两种代码形式 可以总结出二分的两种常用形式
1.r=mid,l=mid+1,取中间值的时候,mid=(l+r)>>1;
2.l=mid,r=mid-1,取中间值的时候,mid=(l+r+1)>>1;

注意
1.如果不对mid的取法进行区分,可能会造成出错的情况,在平时的练习当中,希望大家能注意选择,我不再赘述,《进阶指南》里面讲得很详细啦。
2.在二分当中,我们采用的是右移运算而不是除法,是因为右移运算是向下取整的,但除法向0取整。

终止条件:l==r 也就是答案所在的位置啦

实数域上的二分

实数域会方便很多,具体两种方法。

1.给出精度eps 以l+eps<r为条件

while(l+eps<r)
{
//自己写啦!
}

2.暴力循环100次 完全不用担心不够 2^100已经超过了int类型~
for(int i=0;i<100;i++)
{
//自己写.jpg
}

关于二分的知识点大概就是上面这些,但是大家在写代码的时候一定要注意各种边界条件,比如说l和r之间可不可以取等号,又或者mid是+1,-1还是不加不减。
我个人感觉二分当中的坑点很多,反正我经常因为各种乱七八糟的边界条件debug老半天,肯定是编译器的锅!可能我还是比较菜对题目/模板的理解不够深......

下面给出两道练习题
洛谷P1873砍树 题解(附带原OJ链接)

洛谷P2678跳石头(NOIP2015) 题解(附带原OJ链接)

关于三分

三分,顾名思义就是分成三份,它主要用于求单峰函数的极值。
单峰函数,就是一个有极大值或者极小值的函数。
如果有极大值,那么极大值的左边是单调递增,右边单调递减;
如果有极小值,那么极小值的左边是单调递减,右边是单调递增。
其实我脑袋里面已经自动脑补了一个二次函数了......
(但两者不能划等号哦!二次函数是单峰函数,但单峰函数中仅仅是包含了二次函数)

关于单峰函数求极值的分析

以一个有极大值的单峰函数为例(如图所示)
若此函数有纵坐标y1<y2,那么它横坐标的情况就是两种
1.x1和x2都在极大值的左边,并且x1<x2
2.x1在极大值的左边,x2在极大值的右边
通过分析,我们可以发现,x1总在极大值的左边。
若此函数有纵坐标y1>y2,那么它横坐标的情况也是两种。
1.x1和x2都在极大值的右边,并且x1>x2
2.x1在极大值的左边,x2在极大值的右边
通过分析,我们可以发现,x2总在极大值的右边。
根据以上两种操作,我们可以不停进行三分,直到找到极大值,对于有极小值的单峰函数也是同一个道理。

放两张图在这里,大家自行理解吧......

针对有极大值,且有y1<y2的单峰函数

针对有极小值,且有y1>y2的单峰函数。

qwq三分的知识其实比起二分更简单易懂,因为它能解决的题目范围更狭窄,但需要较强的数学思维,在题目中
能够找出单峰函数的思想。 二分只是一个简单的模板,如果运用到具体的问题当中,要先理清楚这道题有没有二分思想,
同时呢,我认为二分当中的核心应该是check()函数。

下面给出一道题

洛谷P1873 传送带(SCOI2010) 题解(附原OJ链接)

二分的题解就到这里了,很感慨。第一次接触二分我还是一个普及组萌新时根本就看不懂跳石头,甚至完全无法理解......

事实证明,成长的道路上荆棘满布,但只要我们勇敢前行,就没有无法克服的艰难险阻!

原文地址:https://www.cnblogs.com/valentino/p/11161248.html

时间: 2024-10-11 12:49:48

《算法竞赛进阶指南》学习总结 二分与三分的相关文章

《算法竞赛进阶指南》学习总结 #include&lt;algorithm&gt;

今天下午大致学完了进阶指南中algorithm头文件下的内容,在这里进行一个总结.   reverse翻转   顾名思义,reverse进行的操作就是翻转原来的顺序,理解非常简单,故不赘述. 操作样例: #include<bits/stdc++.h> using namespace std; vector<int>a; int b[233]; int main() { int na,nb; //vector的实现 scanf("%d",&na); for

《算法竞赛进阶指南》0.4二分

102. 最佳牛围栏 农夫约翰的农场由N块田地组成,每块地里都有一定数量的牛,其数量不会少于1头,也不会超过2000头. 约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大. 围起区域内至少需要包含 F块地,其中 F会在输入中给出. 在给定条件下,计算围起区域内每块地包含的牛的数量的平均值可能的最大值是多少. 输入格式 第一行输入整数 N和 F,数据间用空格隔开. 接下来 N行,每行输出一个整数,第i+1行输出的整数代表,第i片区域内包含的牛的数目.

《算法竞赛进阶指南》0.8总结与练习(1)

116. 飞行员兄弟 "飞行员兄弟"这个游戏,需要玩家顺利的打开一个拥有16个把手的冰箱. 已知每个把手可以处于以下两种状态之一:打开或关闭. 只有当所有把手都打开时,冰箱才会打开. 把手可以表示为一个4х4的矩阵,您可以改变任何一个位置[i,j]上把手的状态. 但是,这也会使得第i行和第j列上的所有把手的状态也随着改变. 请你求出打开冰箱所需的切换把手的次数最小值是多少. 输入格式 输入一共包含四行,每行包含四个把手的初始状态. 符号"+"表示把手处于闭合状态,而

算法竞赛进阶指南做题记录

基本算法 递归与递推 费解的开关 Strange Towers of Hanoi Sumdiv Fractal Streets 前缀和与差分 激光炸弹 IncDec Sequence Tallest Cow 二分 Best Cow Fences 排序 Cinema 货舱选址 七夕祭 Running Median 第K大数 Ultra-QuickSort 奇数码问题 原文地址:https://www.cnblogs.com/Maktub-blog/p/11009723.html

算法竞赛进阶指南 走廊泼水节

原题链接 题目描述 给定一棵N个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小生成树仍然是这棵树. 求增加的边的权值总和最小是多少. 输入格式 第一行包含整数t,表示共有t组测试数据. 对于每组测试数据,第一行包含整数N. 接下来N-1行,每行三个整数X,Y,Z,表示X节点与Y节点之间存在一条边,长度为Z. 输出格式 每组数据输出一个整数,表示权值总和最小值. 每个结果占一行. 数据范围 \(N \le 6000,Z \le 100\) 输入样例: 2 3 1 2 2 1

bzoj 1787 &amp;&amp; bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南

题目描述 原题连接 Y岛风景美丽宜人,气候温和,物产丰富. Y岛上有N个城市(编号\(1,2,-,N\)),有\(N-1\)条城市间的道路连接着它们. 每一条道路都连接某两个城市. 幸运的是,小可可通过这些道路可以走遍Y岛的所有城市. 神奇的是,乘车经过每条道路所需要的费用都是一样的. 小可可,小卡卡和小YY经常想聚会,每次聚会,他们都会选择一个城市,使得3个人到达这个城市的总费用最小. 由于他们计划中还会有很多次聚会,每次都选择一个地点是很烦人的事情,所以他们决定把这件事情交给你来完成. 他们

《算法竞赛进阶指南》打卡活动 #0x00 基本算法

101. 最高的牛 题目链接:https://www.acwing.com/problem/content/103/ 作为一个银牌水平的主演数据结构的演员来说,这题现在发现非常好想,每个牛分配一个优先度.我搞一个区间线段树,每次update中间一段使得他们的优先度整体下降到比两端中较小的优先度还要小.然后反过来按照优先度分配身高.哈哈!根本不需要什么算法.不过每次都不询问为什么要线段树呢?差分不香吗?当然不香,每次询问当前的优先度啊! const int MAXN = 10000; int re

《算法竞赛进阶指南》刷题记录

总算闲下来一些辣!然后最近发现其实看书是真真很有效但是一直没有落实!所以决定落实一下这段时间把这本书看完题目做完! 然后发现还有挺多题目挺巧妙的于是一堆博客预警,,,可能最近会写很多比较水(但是我还是不会做)的题目的题解 先放个空壳子晚上再来写qwq 原文地址:https://www.cnblogs.com/lqsukida/p/9988445.html

【算法竞赛进阶指南】USACO07Tallest Cow

前缀和,利用左右端点操作代替对区间的操作,从而优化输入,最后进行一次前缀和的操作,求得结果,这道题里面有个很关键的问题,就是需要去重,本来我想用set,但貌似有点鬼畜,算了,利用map去重,还有pair类型(学一下) #include <iostream> #include <algorithm> #include <map> #include <utility> using namespace std; map<pair<int,int>