注意事项
一般 check 函数只能判断是否合法,没有等于这个概念。所以下面两个例子虽然可以通过改变判断符号进行相互转化,但实际问题是不行的。
最大值最小
给定一个不降的序列 \(a\),查找其中大于等于 \(x\) 的第一个数。
其实就是查找第一个合法的点。
while(l<r)
{
mid=(l+r)>>1;
if(a[mid]<x)l=mid+1;
else r=mid;
}
如果当前 \(mid\) 小了,就向右寻找,当前 \(mid\) 不可能是答案,可以直接忽略,以 \(mid+1\) 为新的左端点。
如果当前 \(mid\) 大于等于了,就向左寻找,当前 \(mid\) 可能是答案,不可以直接忽略 \(mid\),应该以 \(mid\) 为新的右端点。
初始条件默认 \(l\leq r\)。因为是整除 \(\bm 2\),所以在循环中 \(mid\in[l,r),mid+1\in(l,r]\),不会死循环也不会跳出 \([l,r]\)。
所以最后 \(l=r\),即为所求。
最小值最大
给定一个不降的序列 \(a\),求其中小于等于 \(x\) 的最后一个数。
其实就是查找最后一个合法的点。
while(l<r)
{
mid=(l+r+1)>>1;
if(a[mid]>x)r=mid-1;
else l=mid;
}
如果当前 \(mid\) 大了,就向左寻找,当前 \(mid\) 不可能是答案,可以直接忽略 \(mid\),以 \(mid-1\) 为右端点。
如果当前 \(mid\) 小于等于了,就向右寻找,当前 \(mid\) 可能是答案,不可以直接忽略,应该以 \(mid\) 为新的左端点。
初始条件默认 \(l\leq r\)。因为是加 \(\bm 1\) 后整除 \(\bm 2\),所以在循环中 \(mid\in(l,r],mid-1\in[l,r)\),不会死循环也不会跳出 \([l,r]\)。
所以最后 \(l=r\),即为所求。