二分

定义:二分的基础用法是在单调序列或者单调函数中进行查找。
根据复杂度理论,我们可以通过将求解改为判定的方法,优化算法。这是一种非常基础,又比较容易写错的算法。本文将阐述一种常见的二分方法。

整数集合上的二分

保证最终答案处于闭区间 $ [l,r] $ 以内,循环以 $ l == r $ 结束,每次二分的中间值会归属于左半段或者右半段。

应用
单调递增序列求 $ x $ 或 $ x $ 的后继:

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

单调递增序列求 $ x $ 或 $ x $ 的前驱:

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

注意:可行解一定要在选取的区间之内,一定不能造成没有缩小可行区域的情况

如上面两种代码所示,这种闭区间的二分有两种形式

  1. 缩小范围时,$ r = mid $, (l = mid + 1),取中间值时,(mid = (l + r) / 2)
  2. 缩小范围时,$ l = mid $, (r = mid - 1),取中间值时,(mid = (l + r + 1) / 2)

思考一下,如果第二种情况仍然使用 (mid = (l + r) / 2), 如果 (r - l == 1) 那么 (mid) 的值就会和 (l) 一样,会造成没有缩小可行区域的情况,进入死循环
仔细分析这两种 (mid) 的取值,我们还发现:(mid = (l + r) / 2) 不会取到 (r) 这个值,(mid = (l + r + 1) / 2) 不会取到 (l) 这个值。我们可以利用这一性质来处理无解的情况,即:把最初的二分区间 ([1,n]) 变成 ([0,n]) 或者 ([1, n+1]),如果最终结果在这两个不存在的值上,那就是没有答案。
因此,使用配套(mid) 取法时必须的。

至此,整数域的二分已经讲完,采用" (l = mid + 1, r = mid - 1) " 或 “ (l = mid, r = mid) "的代码形势也很常见,但是在这里不做过多的阐述

实数域上的二分

实数域上的二分比较简单,设置精度,然后直接二分就可以。

while (l + eps < r) {
    double mid = (l + r) / 2;
    if (calc(mid)) r = mid; else l = mid;
}
原文地址:https://www.cnblogs.com/Alessandro/p/9709649.html