二分

前言

答案属于一个区间,当这个区间很大时,暴力超时。但重要的是这个区间是对题目中的某个量有单调性的,此时,我们就会二分答案。每一次二分会做一次判断,看是否对应的那个量达到了需要的大小。

模板

模板1

while (l < r)
{
    int mid = l + r >> 1;	//(l+r)/2
    if (check(mid))  r = mid;    // check()判断mid是否满足性质
    else l = mid + 1;
}

模板2:

while (l < r)
{
    int mid = l + r + 1 >> 1;	//(l+r+1)/2
    if (check(mid))  l = mid;
    else r = mid - 1;
}

第一个模板是尽量往左找目标,第二个模板是尽量往右找目标。
只要是往左找答案,就用第一个模板,mid不用加一,r=mid,l加一;
只要是往右找答案,就用第二个模板,mid要加一,l=mid,r要减一;

模板3:(浮点二分)

while(r-l>1e-5) //需要一个精度保证
{
	double mid = (l+r)/2;
	if(check(mid)) l=mid; //或r=mid;
	else r=mid; //或l=mid;
}

浮点二分就相对简单多了,因为浮点除法不会取整,所以mid,l,r,都不用加1或减1.

函数

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a[1000]={};
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
	int m;
	cin>>m;
	for(int i=1;i<=m ;i++)
	{
		int b;
		cin>>b;
		cout<<lower_bound(a+1,a+1+n,b)-a<<endl;//第一个大于等于 无 返回>n
		cout<<upper_bound(a+1,a+1+n,b)-a<<endl;//第一个大于
		cout<<binary_search(a+1,a+1+n,b)<<endl;//有 1,无 0
	}
	return 0;
}

二分答案

如何判断一个题是不是用二分答案做的呢?

  1. 答案在一个区间内(一般情况下,区间会很大,暴力超时)
  2. 直接搜索不好搜,但是容易判断一个答案可行不可行
  3. 该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。

此外,可能还会有一个典型的特征:

求...最大值的最小 、 求...最小值的最大。

  1. 求...最大值的最小,我们二分答案(即二分最大值)的时候,判断条件满足后,尽量让答案往前来(即:让r=mid),对应模板1;
  2. 同样,求...最小值的最大时,我们二分答案(即二分最小值)的时候,判断条件满足后,尽量让答案往后走(即:让l=mid),对应模板2;
posted @ 2024-11-27 21:40  流氓兔LMT  阅读(22)  评论(0)    收藏  举报