首页 > 其他分享 >知识点扫盲:二分答案

知识点扫盲:二分答案

时间:2024-11-10 22:58:17浏览次数:1  
标签:二分 知识点 int long 扫盲 满足 答案 define

本条博客以及本系列用于记录算法学习中不熟悉或少见的知识点

一.关于二分答案的来源和应用

  1. 由于本大一 == 蒟蒻 == 没有经过系统性的学习,在一场牛客小白月赛中首次听说二分答案这一操作,十分震惊其效率与作用,遂写此篇来记录

  2. 关于二分答案有关的概念[二分法]"https://oi-wiki.org//basic/binary/#二分法"

  3. 简单来说:解题的时候往往会考虑枚举答案然后检验枚举的值是否正确。若满足单调性,则满足使用二分法的条件。把这里的枚举换成二分,就变成了「二分答案」。

  4. 需要注意:二分法的应用场景:满足单调性或需要最大值最小化。
    注意,这里的有序是广义的有序,如果一个数组中的左侧或者右侧都满足某一种条件,而另一侧都不满足这种条件,也可以看作是一种有序(如果把满足条件看做 1,不满足看做 0,至少对于这个条件的这一维度是有序的)。换言之,二分搜索法可以用来查找满足某种条件的最大(最小)的值。

要求满足某种条件的最大值的最小可能情况(最大值最小化),首先的想法是从小到大枚举这个作为答案的「最大值」,然后去判断是否合法。若答案单调,就可以使用二分搜索法来更快地找到答案。因此,要想使用二分搜索法来解这种「最大值最小化」的题目,需要满足以下/三个条件/:

1.答案在一个固定区间内;

2.可能查找一个符合条件的值不是很容易,但是要求能比较容易地判断某个值是否是符合条件的;

3.可行解对于区间满足一定的单调性。换言之,如果 x 是符合条件的,那么有 x + 1 或者 x - 1 也符合条件。(这样下来就满足了上面提到的单调性)
当然,最小值最大化是同理的。

二、经典例题(难度不大)

e.g1. [洛谷p2440木材加工]"https://www.luogu.com.cn/problem/P2440"

e.g2. [P4058 [Code+#1] 木材]"https://www.luogu.com.cn/problem/P4058"

[Code+#1] 木材

题目描述

有 $n$ 棵树,初始时每棵树的高度为 $H_i$,第 $i$ 棵树每月都会长高 $A_i$。现在有个木料长度总量为 $S$ 的订单,客户要求每块木料的长度不能小于 $L$,而且木料必须是整棵树(即不能为树的一部分)。现在问你最少需要等多少个月才能满足订单。

输入格式

第一行 $3$ 个用空格隔开的非负整数 $n,S,L$,表示树的数量、订单总量和单块木料长度限制。

第二行 $n$ 个用空格隔开的非负整数,依次为 $H_1,H_2, ... ,H_n$。

第三行 $n$ 个用空格隔开的非负整数,依次为 $A_1,A_2, ... ,A_n$。

输出格式

输出一行一个整数表示答案。

样例 #1

样例输入 #1

3 74 51
2 5 2
2 7 9

样例输出 #1

7

提示

对于样例,在六个月后,各棵树的高度分别为 $14,47,56$,此时无法完成订单。

在七个月后,各棵树的高度分别为 $16,54,65$,此时可以砍下第 $2$ 和第 $3$ 棵树完成订单了。

以下为eg2的代码及本人在2024.11.10因两个测试点数十次wonderful answer 后的经验与教训

```
#include<bits/stdc++.h>//需要对n==1时进行特判
#define N 200005
#define mod 998244353
#define int unsigned long long
using namespace std;
typedef long long ull;
int n,s,l;
//priority_queue<int,vector<int>,greater<int> >q;
int a[N],b[N],c[N];
bool check(int x)
{
    int b2 = x;
    for(int i = 1; i <= n;i++)
    {
        c[i] = x*b[i] + a[i];
    }
    int sum = 0;
    for(int i = 1;i <= n;i++)
    {
        if(c[i] >= l)   sum += c[i];
    }
    if(sum >= s) return true;
    else    return false;
}
void solve()
{
    cin>>n>>s>>l;
    for(int i = 1;i <= n;i++)   cin>>a[i];
    for(int i = 1;i <= n;i++)   cin>>b[i];
    if(n == 1)
    {
        c[1] = a[1];
        if(s <= a[1])
        {
            cout<<0;
        }
        else
        {
            ull ans = 0;
            ans = (s-a[1])/b[1];
            cout<<ans<<"\n";
        }    
        return ;
    }
    int l = 0,r = 1e18;//此处应注意,l不设置-1的原因是我使用了ull
    while(l < r)
    {
        int mid = (l+r)/2;
        if(check(mid))  r = mid;
        else    l = mid+1;
    }
    cout<<l<<"\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    solve();
    return 0;
}
```
![alt text](image.png)
![alt text](image-1.png)

但是关于此处,本人还是不太理解,为何将l<=r与r = mid-1 改为 l < r 与 r = mid就能将tle的#16过掉 (是宇宙射线

e.g3 [小红打怪]"https://ac.nowcoder.com/acm/contest/94879/C"

/本题为萌新较难看出来的二分答案~~其实是因为我太蒟蒻~~/


注意力不太集中的同学也可以观察到,因为本题单调性显然成立,或者说,满足

需要将最大值最小化,假设最少第x次可以将所有怪物击杀,那么第x+1显然能

将所有怪物击杀,因此可以使用二分答案的方式进行处理;


贪心有关的内容:先欠着

容易得到代码

```
#include<bits/stdc++.h>
#define N 200005
#define mod 998244353
#define int long long//恶毒的写法,不要轻易使用
using namespace std;
typedef long long ll;
int n,a[N],b[N];
bool check(int x)
{
    int b2 = x;
    for(int i = 1;i <= n;i++)
    {
        b[i] = max(a[i]-b2,0ll);//因为怪物血量不能为0
    }
    int t = 0x3f3f3f;
    for(int i =1;i <= n;i++)
    {
        t = min(b[i],b[i+1]);
        b2 -= t;
        b[i] -=t;
        b[i+1] -=t;
    }
    b2 +=x;//易得,若相邻的次数有剩,则剩下的即为单体打击
    for(int i =1 ;i <= n;i++)
    {
        b2 -=b[i];
    }
    return b2>=0;//最后若为真,则说明目前的回合数位于x右侧
}
void solve()
{
    cin>>n;
    for(int i = 1;i <= n;i++)   cin>>a[i];
    int l=0,r = 1e9;//这里的1e9与数据范围有关
    while(l <= r)
    {
        int mid = (l+r)/2;
        if(check(mid))   r = mid-1;
        else    l = mid+1;
    }
    cout<<l<<"\n";
}
signed main()
{
    ios::sync_with_stdio(false);//关闭流同步
    cin.tie(nullptr);//此处注意
    cout.tie(nullptr);//若报错,则说明c++版本过低,~~建议更换c++20或c++23~~
    solve();
    return 0;
}
```

标签:二分,知识点,int,long,扫盲,满足,答案,define
From: https://www.cnblogs.com/graspppp/p/18538654

相关文章

  • ABC372D ABC379F 题解 单调栈二分
    ABC372DABC379F题解单调栈二分一直觉得AT上面学到的东西比CF要多一些,无意捧一踩一,但可能是我太菜的原因,毕竟ABC的题目普遍要比Div.2简单一些。好多次碰到这个单调栈里面二分的trick了,所以写一篇来总结一下。ABC372D形象地给定一系列Buildings的高度\(h\),保证每个......
  • 二分 笔记
    二分一般来讲我们可能会在以下情况用二分:求单调函数的零点,或者找个值(二分查找)求一堆东西的最小值最大(或是最大值最小)是多少(二分答案)很难直接算出答案,但是很好判定答案合不合法对于单峰函数,可用二分导函数来代替三分二分查找二分是一种可以在\(O(chlogm)\)(m为数据规模,ch为......
  • 课程讲解--深入探究二分算法
     一、二分查找算法的基本概念定义与原理二分查找,也被称为折半查找,是一种在有序数据集合中查找特定元素的高效算法。其原理基于分治思想,每次查找都将查找区间缩小一半。例如,在一个有序数组中查找一个特定的数字,我们先比较数组中间位置的元素与目标元素的大小。如果中间元素......
  • 【算法基础篇】二分算法
    二分算法二分算法基本介绍应用场景例题进击的奶牛小红打怪总结二分算法基本介绍二分查找算法(BinarySearch)是一种高效的查找算法,特别适用于在有序数组或列表中快速定位目标元素。它利用了分治法的思想,每次查找都将搜索范围缩小一半,因此时间复杂度为O(logn),效率......
  • np.random.randint知识点
    函数概述np.random.randint是NumPy库中的一个函数,用于生成随机整数。它可以在指定的区间(左闭右开)内生成一个或多个随机整数。函数语法np.random.randint(low,high=None,size=None,dtype='l')参数解释:low:生成的随机整数的最小值(包含该值)。如果high为None,则low为......
  • 知识点:动态规划
    知识点:该题目考察的知识点是动态规划,特别是用于计算两个字符串之间的编辑距离(Levenshtein距离)。编辑距离是衡量两个字符串相似度的一种方法,它定义为将一个字符串转换为另一个字符串所需的最少操作次数,这些操作包括插入、删除和替换字符。动态规划的相关内容:动态规划是一种算法策......
  • 知识点:算法策略
    知识点:在软考中,常考的算法策略包括分治法、动态规划法、贪心法、回溯法等。下面详细介绍这些算法策略的原理、适用场景以及算法复杂度:1.分治法原理:分治法是将一个复杂的问题分解成若干个相同或相似的子问题,递归解决子问题,然后将子问题的解合并以解决原问题。适用场景:适用于可......
  • 网络安全技术概论知识点
    目录第一章网络安全基础知识点例题第二章网络安全技术基础知识点第三章网络安全体系管理知识点例题第四章黑客攻防与检测防御知识点例题第五章、第六章第七章计算机及手机病毒防范例题第八章防火墙技术知识点第九章操作系统安全第十章数据库及数据安全知识点第......
  • 知识点:用例图(Use Case Diagram)
    知识点:该题目考查的是面向对象的分析与设计方法(Object-OrientedAnalysisandDesign,OOAD),特别是用例图(UseCaseDiagram)的相关知识点。用例图是UML(统一建模语言)中的一种图表,用于描述系统的功能需求,它展示了系统如何与外部用户或其他系统交互。知识点相关内容:用例(UseCase):用......
  • 动态内存的相关知识点
    今天学了动态内存管理的相关知识点,首先什么是动态内存呢,我的理解是可大可小的,能够动态变化的。1.为什么存在动态内存分配我们已经掌握的内存开辟方式有:intmain(){ inta=10; intarr[10]={0}; intn; scanf("%d",&n); intarr1[n]; return0;}向上面......