参考:李煜东《算法竞赛进阶指南》
整数集合上的二分
int bsearch_1(int x, int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (a[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
int bsearch_2(int x, int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (a[mid] <= x) l = mid;
else r = mid - 1;
}
return l;
}
- 这两种写法保证最终答案位于
[l, r]
内,且结束时l = r
- 要与相应的
mid
写法对应,否则可能死循环 - 右移运算向下取整,整数除法向零取整(二分域包含负数时无法正常工作)
- 要通过分析具体问题,确定左右区间哪个是可行区间,以及
mid
应归属哪一半,来选择两个形式之一
例题:AcWing 789. 数的范围
实数域上的二分
const double eps = 1e(-k);
double bsearch_3(double l, double r)
{
while (l + eps < r)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
例:AcWing 790. 数的三次方根