二分
二分查找
在序列中寻找查找一个符合的元素通常为 \(O(n)\),即一次暴力枚举.在保证元素单调情况下,可以使用二分以“查字典”的方式一半一半地筛去不符合的元素,以 \(O(\log n)\) 的速度查找一个元素,也可以求解包括但不限于:单调递增递减的函数(如一次函数),插入排序二分优化.
(传统的 \(mid=(l+r+(k))>>1\) 可能带来负数溢出,可进一步改为 \(mid=(l\land r)+((l\oplus r)>>1)\)从而避免)
整数模板一
找大于等于该数的第一个数
int find_high(int x){
int l=1,r=n,mid;
while (l < r){
mid = (l&r)+((l^r)>>1);
if (a[mid]>=x) r = mid;
else l = mid + 1;
}
return a[l];
};
整数模板二
找小于等于该数的第一个数
int find_low(int x){
int l=1,r=n,mid;
while (l < r){
mid = (l&r)+((l^r)>>1)+1;
if (a[mid]<=x) l = mid;
else r = mid - 1;
}
return a[l];
};
实数模板
大于等于的第一个数
int find_high(double x){
int l=1,r=n,mid;
while (r>l+esp){
mid = (l&r)+((l^r)>>1);
if (a[mid]>=x) r = mid;
else l=mid+1;
}
return a[l];
};
小于等于的第一个数
int find_low(double x){
int l=1,r=n,mid;
while (r>l+esp){
mid = (l&r)+((l^r)>>1)+1;
if (a[mid]<=x) l = mid;
else r = mid - 1;
}
return a[l];
};
二分答案
当题目求最大(小)可行的条件时,当参数与返回值成正相关或负相关时可以使用二分答案求解。
例题河中跳房子解:
求最短跳跃距离,由题意可得跳跃距离 \(l\in [1,L]\),由于 \(L\le 10^9\),在贪心超时,剪枝较困难时,采取二分,策略为以 \(1\) 为左边界, \(L\) 为右边界,二分枚举,复杂度 \(O(N\log_2 L)\approx O(30N)\)。

浙公网安备 33010602011771号