【基础算法】二分

4.二分

适用条件:具有单调性的问题。

4.1.STL

在从小到大的排序数组中:

lower_bound(begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound(begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

在从大到小的排序数组中,重载lower_bound()和upper_bound():

lower_bound(begin,end,num,greater<type>()):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

upper_bound(begin,end,num,greater<type>()):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

4.2.整数集合上的二分

4.2.1.整数集合上的二分

  • l=mid?r=mid?

    令长度为2的区间l=1,r=2。看是l=mid还是r=mid会缩小为长度为1区间。

  • 保左?保右?

    代码

    令长度为2的区间l=1,r=2。如果mid是偏向l(r),则该二分是保左(右)。

    如果mid是恰好可行的(==)且保左(右),就令r=mid(l=mid)。(因为mid本身就是偏左(右))

    问题

    保左(右):边界mid在答案位置ans的左(右)边。 此时l(r)会向mid的右(左)边一单位跳到答案位置。

    4种情况(0代表check(mid)=false,1代表true):01找最后一个0、01找第一个1、10找最后一个1、10找第一个0。

    根据问题选择保左的二分还是保右的二分。

  • 无解?

    对于保左写法(mid=(l+r)>>1),mid不会取到r这个值,因此可以把最初的二分区间[1,n]扩大为[1,n+1],若最终l==n+1,无解。

    对于保右写法(mid=(l+r+1)>>1),mid不会取到l这个值,因此可以把最初的二分区间[1,n]扩大为[0,n],若最终l==0,无解。

在单调序列a中查找≥x最小的一个(x或x的后继、01找第一个1、10找第一个0),保左:

while(l<r)
{
    int mid=(l+r)>>1;
    if(a[mid]>=x) r=mid;
    else l=mid+1;
}
return a[l];//思维:此时l==r

在单调序列a中查找≤x最大的一个(x或x的前躯、01找最后一个0、10找最后一个1),保右:

while(l<r)
{
    int mid=(l+r+1)>>1;
    if(a[mid]<=x) l=mid;
    else r=mid-1;
}
return a[r];//思维:此时l==r

4.2.2.二分答案转为判定

这个思想在很多算法中都有涉猎。

适用条件:具有“单调性”值域的问题:
设定义域为该问题下可行方案,则值域为该方案的评分,最优解就是评估分最高S的方案。\(\forall x>S\),都不存在一个合法的方案达到x分;\(\forall x≤S\),一定存在一个合法的方案达到或超过x分。
又或者说方案一段全部合法另一段全部不合法。

把最优性问题转化为可行性问题,简化题目。

注意保左保右的问题。详见上文。

技巧

  • 求绝对值|c-x|最小值:可拆成小于c的最大x和大于c的最小x两个子问题。
  • 求check()方案时,要 while(l<r) 循环后 check(l),不可以在while(l<r)循环内的if(check(mid))后记录方案,因为有可能mid一直非法到最后l=r=1就没有记录方案了。

4.3.实数域上的二分

while(r-l>EPS)
{
    double mid=(l+r)/2;
    if(check(mid)) l=mid;//mid还需要再大一点
    else r=mid;//mid还需要再小一点
}
return l;//思维:此时l==r。偶尔取l(或r)会有精度问题,需要换着取r(或l)试试
posted @ 2025-06-23 22:21  Brilliance_Z  阅读(23)  评论(0)    收藏  举报