二分小记

二分的基本用途是在单调序列或单调函数中做查找操作。

二分,顾名思义,是不断将待求解区间平均分成两份,根据求解区间中点的情况来确定目标元素所在区间,这样就把解的范围缩小了一半。

二分算法的复杂度:O(二分次数*单次判定复杂度)

二分的写法:

整数域的二分:
int erfen(这里可以根据需要添加参数){
    int l=二分下界,r=二分上界,ans;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,l=mid+1;//这里求的是最小值最大问题
          else r=mid-1;
    } 
    return ans;
}

实数域的二分:
double erfen(这里可以根据需要添加参数){
    double l=二分下界,r=二分上界,ans;
    while(fabs(l-r)>dlt){
        double mid=(l+r)>>1;
        if(check(mid)) l=mid+1;
          else r=mid-1;
    } 
    return l;
}

二分常见的题型:

1.二分答案:最大值最小,最小值最大的问题:

我举个栗子:

数列分段Ⅱ

典型的二分问题,求最大值最小的问题;

首先确定二分上下界:上界显然不能超过数列中所有数的和,下界是这些数中最大的一个;

二分,套模板,因为是最大值最小的问题,所以不能套上面的二分模板,需要小改动一下,如果判断二分的答案可行,那么二分从l到mid-1;

其实感觉二分难在check函数上(至少我是这么觉得的qwq),因为题目要求是连续的才可以加和,所以我们从a[1]开始加,当某一个a[k]被加上以后超过二分值了,我们另计数器++,表示需要再分一组(小提示:计数器要从1开始记录而不是0),如果计数器<=要分的段数,表示这样分可行,否则不可行;

#include<bits/stdc++.h>

using namespace std;

int n,m,sum,mm;
int a[100010];

bool check(int z){
    int s=0,k=1;
    for(int i=1;i<=n;i++){
        if(s+a[i]>z){
            s=a[i];
            k++;
        }
        else s+=a[i];
    }
    if(k<=m) return 1;
    else return 0;
}

int erfen(){
    int l=mm,r=sum,ans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
          else l=mid+1;
    }
    return ans;
}

int main(){
    scanf("%d%d",&n,&m);
    
    for(int i=1;i<=n;i++)
      scanf("%d",&a[i]),sum+=a[i],mm=max(mm,a[i]);
    
    cout<<erfen()<<endl;
}

2.二分查找;

二分查找一般应用在有序的序列中。

这里不做过多解释qwq

原文地址:https://www.cnblogs.com/zhuier-xquan/p/10987682.html