二分答案与二分查找
二分答案与二分查找
一. 适用范围
如果序列是有序的,就可以通过二分查找快速定位所需要的数据。除此之外,二分思想还能求出可行解的最值问题,如最小的最大值,最大的最小值等等
二.使用方式
二分时首先要确定上下界 \(leftbound\) 以及 \(rightbound\) ,然后取其中间值 \(middle\) , 通过 \(check\)
函数来用 \(middle\) 更新上界或下界
两种不同的代码构造
void erfen()
{
int l=0,r=1e10;
while(l <= r)
{
int mid = (l + r) / 2;
if(check(mid)) ans = mid , l = mid + 1;
else r = mid - 1;
}
printf("%d",ans);
}
void erfen()
{
int l=0,r=1e10;
while(l + 1 < r)
{
int mid = (l + r) / 2;
if(check(mid)) l = mid;
eles r = mid;
}
printf("%d",l);
}
第一种方式:不使用上下界作为答案,而是在每一次 \(mid\) 成立时刷新答案 \(ans\) ,将 \(mid\) 抛出 \(l\) 和 \(r\) 范围,\([l,r]\) 区间内的每个点都有成为答案的可能,所以只有在区间为空时跳出循环,即循环条件是 \(l<=r\)。
第二种方式:使用上下界作为答案,此时可以发现,\(mid\) 成立时刷新的是 \(leftbound\) ,而不成立时刷新 \(rightbound\) ,\(l\) 在答案内,\(r\) 在答案外。所以答案区间是 \([leftbound,rightbound)\) 左闭右开区间。所以 \(l<r\) 恒成立,当 \(l+1==r\) 时,二分结果已经出现,此时跳出循环,输出 \(l\) 作为答案。故循环条件是 \(l+1<r\) 。
三.注意事项
二分题目有时会精确到小数,此时最好使用第二种二分方式,为确保精度,设 \(eps=10^{-8}\) , 以 \(r-l>eps\) 作为边界条件。此时要注意,\(eps\) 精度不能过大,否则复杂度过高会TLE,一般选择 \(10^{-6}\) 就可以了。
切勿忘记开 long long , 任何题都一样
小数精度模板:
#define eps 1e-8
void erfen()
{
double l=0,r=1e10;
while(r-l > eps)
{
double mid = (l+r)/2.0; //除法要带小数点保精度
if(check(mid)) l = mid;
else r = mid;
}
printf("%.10lf",l);
}