整数二分的模板

整数二分的难点

下标越界问题

首先考虑这样的例子:
从{0,1}中找到1的下标:通常做法是l、r找到边界值0,1,当然也可以从-1、2开始,这通常不是问题;
在考虑结束条件的时候,往往考虑用l代指最后结果的下标。更新l和r用的是mid的取值,在C++等语言中,默认除2操作采用下取整,这就导致,0+1>>1永远是0,假如在找向右区间的时候,令l=mid,会陷入死循环;假如令l=mid+1,似乎解决了l的赋值问题,但是在找向左区间的时候。令r=mid,一样会面临这样的问题(这是由于这种模板利用除法的不对称性,考虑l、r不对称操作来消除)
但是这种显然增加了记忆的负担,考试的时候,边界考虑很让人抓狂,尤其是对齐问题。
下面的模板采取左右区间对称操作,只有当v[mid]和k相等的时候,才会退出,当然,这种二分找到的是严格递增序列中的下标,假如要求必须是下取整,或者上取整,也可以在后面增加向前遍历的操作。

int l=0,r=n-1;
	while(l<=r){
		int mid=l+(r-l)/2;
		if(v[mid]<k)	l=mid+1;
		else if(v[mid]>k)	r=mid-1;
		else{
			l=mid;
			break;
		}
	}
	if(v[l]!=k)	cout<<-1;

至于给出{1,2,2,2,2,2,2,2,2...2,1}总数是10^9这种数据,这样的方法就显然不适用了。这样二分效率不是会很低,但是向前遍历就会很慢了。
于是,解决这一类__下确界__的模板,就变成了,首先,推出条件不在是l>r,而是l>=r,想象l=0,r=1,此时mid=0,当要找1时,主动让l=mid+1;要找0时,主动让r=mid;同时配合mid采用下取整;解决__上确界__当要找1时,主动让l=mid;找0,r=mid-1;配合mid采用上取整;
总之,这个利用上下取整条件的二分模板关键在于,让l自由地指向1的位置,让r指向0的位置,这时再考虑mid是不是要下取整,因为无论去哪里,l和r的分支两端都只差一个下标,这样能够使得__划分完整地遍历到数轴__的每一个值。

posted @ 2025-12-31 17:46  青檀炽羽  阅读(4)  评论(0)    收藏  举报