序
以前学习二分的时候一直没有搞清楚什么时候$mid = (left + right) / 2$,什么时候$mid = (left + right + 1) / 2$,更新的时候是$right = mid + 1$还是$right = mid - 1$,但是一直迷迷糊糊的也能写对题,后面也没有多管。这个寒假重新学一遍基础算法,才明白为什么会有这两种情况。
整数二分的两种情况
第一种 $mid=(right+left+1)/2$
这种情况代码如下
while (l < r) |
为什么$mid$需要补上一个$1$呢?
因为整数的除法是向下取整,我们需要在运算时+1时它变成向上取整,否则的话会因为边界问题导致while无限循环。
举个例子,在区间只有两个数的时候,比如$l=3,r=4,mid=(3+4)/2=3$,这时候如果check成功,那么会执行$l=mid$,然后问题就来了,$l$和$mid$本来就都等于3,然后就会无限循环下去,$l$和$mid$的值永远不会更新。所以在$l=mid,r=mid-1$的更新方式下,我们需要将运算时$mid+1$成为向上取整才不会死循环。
第二种 $mid=(right+left)/2$
这种情况代码如下
while (l < r) |
为什么$mid$在这里不需要补上一个$1$呢?
因为边界问题不会影响到值的更新,还是用上面那个例子,$l=3,r=4,mid=(3+4)/2=3$。
此时如果check成功,那么$l=mid+1=4$,更新成功。如果check失败,则$r= mid=3$,同样更新成功。由此可以看出,在$l=mid+1,r=mid$的更新方式下,不需要对$mid$进行任何操作。
以上是整数二分的两种固定写法。那么什么时候用哪种方法呢,这就要根据具体的题目进行分析了。
例题—— 分巧克力
题目描述
儿童节那天有 K 位小朋友到小明家做客。
小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N 块巧克力,其中第 i 块是 Hi×Wi 的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。
切出的巧克力需要满足:
形状是正方形,边长是整数
大小相同
例如一块 6×5 的巧克力可以切出 6 块 2×2 的巧克力或者 2 块 3×3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含两个整数 $H_i$ 和 $W_i$。
输入保证每位小朋友至少能获得一块 $1×1$ 的巧克力。
输出格式
输出切出的正方形巧克力最大可能的边长。
输入输出样例
输入#1
2 10
6 5
5 6输出#1
2AC代码
|
题目很简单是二分的板子题,主要是说为什么要用第一种求$mid$方法呢。
为什么二分里面不能写成
int mid = l + r >> 1; |
推导一遍发现,如果$check$成立后,说明当前的$mid$值也是在答案范围中,所以答案只能在$[mid,
r]$之中取。理所当然无法用上面那种写法,如果用上面那种方法,$l$会直接更新成$mid+1$,会越过$mid$这个值,所以在一些情况就会出现错误,比如题面的样例$l$就会成为$2+1=3$,越过了$2$这个可能的答案值,恰好$2$就是最大的一个答案,导致答案错误。
总结
这次弄明白了二分的写法属实是不易,留文一篇防止日后遗忘
以后写二分的时候记得注意一下区间情况