二分
二分的两个模板
第一个模板
#这个模板表示check(mid)=1的时候最后的结果可以取到mid 也就是把区间分成 [l,mid]和[mid+1,r]
#这个模板下 如果一直chack(mid)=1; 可以check到左边界 但是check不到右边界
#注意这里模板当中 r=mid 和l=mid+1可以调换位置 不影响 最后的结果 影响结果的只有(l+r)/2 是否加一
while(l<r)
{
int mid=(l+r)/2;
if(check(mid)==1)
{
r=mid;
}
else
{
l=mid+1;
}
}
第二个模板
#这个模板表示check(mid)=1的时候最后的结果可以取到mid 也就是把区间分成 [mid,r]和[l,mid-1]
#这个模板下 如果一直chack(mid)=1; 可以check到右边界 但是check不到左边界 需要特判
while(l<r)
{
int mid=(l+r+1)/2;
if(check(mid)==1)
{
l=mid;
}
else
{
r=mid-1;
}
}
模板选择
首先,就是我们什么时候用二分,对于二分,我在网上看过一个大佬的描述醍醐灌顶,我们二分可以看作是我们给出一个最后的答案看看他是否是符合题意的,然后,根据check的结果决定我们最后的任务。二分的条件,就是我们的答案在某一个分为内单调不增或者单调不减 还有,题意当中出现最大值最小和最小值最大一般可以用二分做(注意不是绝对,只是一个技巧)
然后,就是对于两个模板的选择问题 如果发现某一个题目当中二分的哪个数mid=1的时候 那个mid可能成为答案 那么他就一定是r=mid或者l=mid,然后再去根据题意去判断是要取哪个区间。 反之,如果mid成为不了答案,就采用r=mid-1 或者l=mid+1。
背模板的方式 有减就有加。
模板理解
在刷题过程中,我个人的理解 是二分模板最后得到的答案是一个可能的值,但这个值不一定是就是check(mid)=1的值,也就是说最后的答案并不一定符合条件 ,所以我们最后需要特判一下,看看我们得到的值是否符合条件。
对于这个模板,比较方便的地方在于最后l和r是相同的,所以如果找到了答案直接输出l就可以了 但是 我们要注意两个模板都有check不到的点,也就是没找到的时候。
其实 我们可以这么理解 取不到 边界 我们这个是二分查找某一个符合条件的数 而不是向我们在数据结构当中学习的查找某一个确定的数字。所以最后可能存在找不到情况,比如第一个模板当中的check不到右边界,但是这段代码已经完成他的任务 他帮我们筛选出了可能符合题意的l(也就是最后答案),我们只需要对于这种情况特判一下就可以 。
注意点
对于做题 无脑背模板就可以 但是注意点如下:
- 注意初始的l和r 我们一个很简单的方式就是无脑放大r(当然容易TLE,这时候就要根据题意选择)
- 二分不一定能找到正确的解 二分之后得到的答案也需要特判一下 ;
二分题目:
二分+贪心:
[P2678 NOIP2015 提高组] 跳石头 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
二分+dfs:
P1902 刺杀大使 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
二分加前缀和