二分算法的使用

基础知识

二分查找的复杂度是log(n)的

STL中的二分查找函数

函数有哪些

binary_search(a, a+n, t)        查找 数组a 中是否存在 t ,其返回值为bool值

lower_bound(a, a+n, t)        返回可插入t的最小位置的迭代器,即返回第一处大于/等于 t 的位置的迭代器

a[7]={1, 2, 3, 3, 5, 6, 9};
lower_bound(a, a+7, 3); //其返回位置是第一个3的位置
lower_bound(a, a+7, 4); //其返回位置是第一个5的位置

upper_bound(a, a+7, 3); //其返回位置是第二个3的位置
upper_bound(a, a+7, 4); //其返回位置是第一个5的位置

upper_bound(a, a+n, t)        返回可插入的最大位置的迭代器,即返回第一处大于 t 的位置的迭代器

函数返回的迭代器怎么处理

迭代器其实相当于一个封装过的指针,所以要处理迭代器可以这样:

               int i=lower_bound(a, a+n, t)-a;//此时 i 即为返回值的迭代器所对应的下标

即,使用函数返回值 减去 数组的数组名(代表其首地址)

例题:

NC24866

#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
    int a[7]={1, 2, 3, 3, 5, 6, 9};
    int i=lower_bound(a, a+7, 3)-a;
    printf("i:%d  a[i]:%d", i, a[i]);
    return 0;
}

二分答案+验证

先假设答案的值,带回去验证是否刚好成立,不符合则改变先前所假设的值,再进行判断,最终得出一个刚好满足条件的值

能解决什么问题

解决最大值最小(即让最大值尽可能小) 或者 最小值最大(即让最小值尽可能大)

        解决这两类问题的常见方法为:

        1.贪心(国王游戏)

        2.二分

        3.动态规划

        解决这类问题是: 能二分尽量二分, 不能二分考虑贪心, 不能贪心考虑动态规划,都不能则大概率需要直接用暴力

例题:

NC107701、NOIP2015、NC24724

三分(单峰函数最大值、单谷函数最小值)

01分数规划

补充知识

1.差分数组(待复习)

使用条件

当有频繁的区间修改, 而每次都是对某个区间修改某个值的时候,可以使用差分数组

差分数组的定义

差分数组和 前缀和 一样,是通过对 原数组 进行数学运算得到的 新数组, 前缀和的定义规则是这样的:

        我们先假设一个原数组 arr[5]={1, 3, 5, 7, 9};

        那么我们可以定义一个前缀和数组 q[5]={1, 4, 9, 16, 25};

        这个数组是如何定义实现的呢?其实是这样的:

                q[0]=arr[0];

                q[i]=q[i-1]+a[i];        当 i != 0 时;

​if(i==0)
    q[i]==arr[i];
else
    q[i]=q[i-1]+arr[i];

而差分数组的定义规则是这样的:

        依然我们先假设一个原数组 arr[5]={1, 3, 4, 7, 10};

        那么我们可以定义一个差分数组 c[5]={1, 2, 1, 3, 3};

        差分数组的定义实现是这样的:

                c[0]=arr[0]-0;

                c[i]=arr[i]-arr[i-1];        当 i != 0 时;

if(i==0)
    c[i]=arr[i]-0;
else
    c[i]=arr[i]-arr[i-1]

        即,差分数组的每个元素是=原数组的对应元素-原数组的对应元素的前一项(因为我们定义的原数组是从0开始,所以差分数组第0项是=原数组的第0项-0)

差分数组的用法

现在我们定义好了一个差分数组,那么它对我们来说有什么用呢?

当我们需要让原数组 [l, r] 区间都加上 x 时,正常的处理是遍历数组的 l到r 区间,每次加上 x。这样做,时间复杂度太大了,所以我们可以使用差分,其处理方法是这样的:

        对于区间的左边 l ,我们使 c[l]=c[l]+x

        对应区间的右边 r,我们使 c[r+1]=c[r+1]-x

如此操作,我们便改变了差分数组在 [l,r] 区间上的值,但此时我们如果想使用原数组时,其实原数组的值都还未改变,若需要使用原数组改变后的值,那我们可以这样做:

        遍历原数组arr[n]

        a[0]=c[0]+0;

        a[i]=c[i]+a[i-1];        当 i != 0 时

其实这个操作是什么呢?就是差分数组定义的逆应用。这样我们就得到了一个改变后的数组。

2.主席树(函数式线段树 | 待学 )

【AgOHの数据结构】主席树_哔哩哔哩_bilibili

3.线段树(待学)

4.尺取

尺取,就是在求满足条件的连续子区间时,通过移动子区间的左右边界去得到一个满足条件的区间

其具体实现操作是这样的:

        我们先假设满足条件区间的左边界是 l, 右边界是 r。我们想去找满足条件的区间,则l 和 r应该从起点开始移动,即 l=r=0

        接下了我们的操作是这样的,我们先判断当前区间满不满足条件。当当前[l, r] 区间不满足条件时, r++, 即右边界变大;当当前[l, r]区间满足条件时, l++, 即左边界变大。

        最终,当我们遍历到l=n时,就结束了

5.unique函数(去重函数)

6.fined

7.setprecision();

有多(t)组测试数据时,一定要用while(t--)。写NC14301时,被坑死了,检查了所以可能错的地方,就是没发现用for循环时,内层和外层的循环变量是一样的。。。(直接哭晕在厕所了T_T)

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值