【小心地雷!】关于二分方法的不同与代码细节

发布时间 2023-06-09 15:46:57作者: fanghaoyu801212

【小心地雷!】关于二分方法的不同与代码细节

笔者写这道题,调了30min发现二分挂了qwq,故作此文。
众所周知,一般情况下,二分的方式有两种:
1.区间收缩方式是\(l = mid + 1,r = mid 或l = mid,r = mid - 1\),以\(l = r\)为终点,一般是用于“可行”答案的最值寻找,如果\(mid\)可行,找最大值就将\(l = mid\),最小值就将\(r = mid\),最终\(l = r\)时就是答案,代码(仅作示范):

inline int find(int x)
{
    int l = 1,r = n;
    while(l < r)
    {
        int mid = (l + r) >> 1;
        if(cando(mid,x)) r = mid;
        else l = mid + 1;
    }    
    return l;
}

还有一种办法,就是每次二分时单独用一个“答案”变量,记录取到的最小\大值是多少,因为已经”记“住了答案,所以每次二分时相当于在"新"的\(l \to r\)值域中查找有没有取值,通常用于一种没有“合法性”的问题中,例如,我们知道一种函数\(f(l,r)\)随着\(r - l\)的增大而减小(非线性),现在对于\(x,y\),我们要找到对于\(p \in [x,y - 1]\)\(min(f(x,p),f(p + 1,y))\)的最大值,相当于是要找到一个值,使两边的函数值最接近,代码如下:

inline int find(int x,int y)
{
    int l = x,r = y - 1,ret = 0;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        int lt = f(x,mid),rt = f(mid + 1,r);
        ret = max(ret,min(lt,rt));
        if(lt < rt) r = mid - 1;
        else l = mid + 1;
    }
    return ret;
}