【Acwing蓝桥杯笔记】2.1二分与前缀和&2.1.1 二分法(整数二分/实数二分)

2.1二分与前缀和

2.1.1 二分

什么是二分:

①确定一个区间,使得我们要找的目标值一定在这个区间里面。

②找一个性质,满足:

(1).性质具有二段性(前半段满足,后半段不满足,两段之间无缝连接)

(2).答案是二段性的分界点

整数二分的特点:它的取值是离散的,也许是左半段的右端点,也许是右半段的左端点。

①整数二分

二分的分类以及如何进行二分操作:

  • 第一类:答案是前半段区间的右端点

image-20220303212651255

将 [L,R] 分成 [L,M-1] 和 [M,R]

如果M是红色的,说明答案必然在[M,R]之间,否则答案必然在[L,M-1].

模板如下:

while(L<R)

{

M=(L+R+1)/2;

if (M为红色) L=M;

else R=M-1

}

  • 第二类:答案是绿色区间的左端点

将[L,R]分成[L,M]和[M+1,R],

如果M是绿色的,说明答案在[L,M]之间,否则答案在[M+1,R]之间。

模板如下

while(L<R)

{

M=(L+R)/2;

if(M为绿色) R=M;

else L=M+1;

}

【整数二分总结】

1.找一个区间[L,R],使得答案一定在该区间中

2.找一个判断条件,使得该判断条件具有二段性,并且答案一定是该二段性的分界点。

3.分析终点M在该判断条件下是否成立,如果成立,考虑答案在哪个区间;如果不成立,考虑答案在哪个区间。

4.如果更新方式写的是R=Mid,则不用做任何处理;如果更新方式写的是L=Mid,则需要在计算Mid时加上1。

补充:

二分法使用的条件

查找目标明确,已知查找范围,每次可舍弃一半,状态有穷尽。

一道例题:

image-20220309164355821

若n是数组长度,那么所有数必然是从0到n-1.

①找左端点:大于等于x的第一个位置。

区间范围从0到n-1

判断条件:q[mid] ≥ x L=R

q[R]≠x,说x不存在

否则说明,L,R是x的左端点

②找右端点:

区间范围:左边界(包含左边界)到n-1

判断条件:q[mid]≤x L=mid

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int n,m;
const int N=1000010;
int st[N];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)   scanf("%d",&st[i]);
    for(int i=0;i<m;i++)
    {
        int l=0; int r=n-1;
        int x;scanf("%d",&x);
        //起始位置的确定
    while(l<r)
    {
        int mid=l+r>>1;
        if(st[mid]>=x) r=mid;
        else l=mid+1;
    }
    if(st[l]==x)
    {
        cout<< l <<" ";
        //最终位置确定
        r=n-1;
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(st[mid]<=x)l=mid;
            else r=mid-1;
        }
        cout<< r <<endl;
    }
    else cout<<"-1 -1"<<endl;
    }
    return 0;
}
②实数二分

整数二分的边界条件是当区间内只有一个数的时候停止;而实数二分的边界是当区间长度足够小的时候停止。

因为实数是稠密的,将区间[L,R]划分成[L,M]和[M,R],一般情况下,当区间长度R-L小于1e-6时,二分操作停止。

while(R-L>1e-6)

{

double M=(L+R)/2;

if ans在[M,R]之间,L=M

​ else if ans在[L,M]之间,R=M

}

一道例题:

image-20220402201949120

具有单调性的可以二分,可以二分的不一定具有单调性。

判断条件:若所取的中点M的三次方大于等于此浮点数,则R=M 否则 L=M。

代码如下:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;


int main()
{
    double x;
    cin>>x;
    double l=-10000,r=10000;
    while(r-l>1e-8)//多取两位保险
    {
        double mid=(l + r)/2;
        if(mid*mid*mid>=x)  r=mid;
        else l=mid;
    }
    printf("%lf\n",l);//lf默认保留6位小数
    return 0;
}
③三分法

三分法只适用于单峰或者单谷函数。

image-20220402212112484

大部分的此类函数,求导之后的斜率都是单调的

斜率即是后一个数减去前一个数的差值,我们依次去判断这个差值,然后进行二分。(二分法)

对于三分法,是要找出两个三等分点

那么就会对应三种情况

  1. ML<=MR L=ML
  2. ML>MR R=MR
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2.1.1中,我们将讨论xx功能模块的设计。首先,我们需要明确xx功能模块的目标和用途。根据需求分析,该功能模块是为了解决xxx问题,并提供相应的解决方案。 在设计该功能模块时,我们需要考虑以下几个方面。首先,我们需要确定该功能模块的输入和输出。即用户将如何使用该功能模块,并希望获得哪些结果。这将帮助我们更好地定义模块的功能和范围。 其次,我们需要设计该功能模块的算法和逻辑流程。根据需求,我们可以确定模块需要执行的具体操作和步骤。这将帮助我们确定模块的具体实现方式,并确保其能够满足用户的需求。 此外,我们还需要考虑该功能模块的可扩展性和灵活性。随着需求的变化,该模块可能需要不断地进行修改和扩展。因此,在设计过程中,我们应该采用合适的设计模式和架构,使得模块的修改和扩展变得更加容易和可行。 最后,我们还需要考虑该功能模块与其他模块的集成和交互。在系统中,不同的模块之间需要进行数据的传递和共享。因此,在设计过程中,我们需要明确该功能模块与其他模块之间的接口和协议,以确保它能够无缝地与其他模块进行交互。 综上所述,xx功能模块的设计是一个综合考虑多个因素的过程。通过明确模块的目标和用途、设计算法和逻辑流程、考虑可扩展性和灵活性以及与其他模块的集成和交互,我们可以设计出一个满足用户需求的高效可靠的xx功能模块。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AKA山风点火

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值