【蓝桥】二分法

二分法

简介:

网上模板很多,看得眼花缭乱,搞得不知道用哪种好,我自己就用这种吧,这是前几天看那道冶炼金属那题看到得模板,这个模板应该也适用于很多题了(闭区间)

  • 寻找靠左的数
cpp 复制代码
while(l<=r)
{
    int mid=l+((r-l)>>1);
    if(a[mid]>=x)r=mid-1;
    else l=mid+1;
}
if(a[l]==x)return l;
else return -1;


由上面的图示可以看成,如果是寻找左边的数最终的while(l<=r)最终结束的条件是r在左侧,而l在右侧,因此q[l]==x,那么我们就找到了我们想要且靠左的数的位置

  • 寻找靠右的数
cpp 复制代码
while(l<=r)
{   
    int mid=l+((r-l)>>1);
    if(a[mid]<=x)l=mid+1;
    else r=mid-1;
}
if(a[r]==x)return r;
else return -1;


由这个图示可知,如果要寻找右边的数,最终while(l<=r)的结束条件是r在左侧,l在右侧,那么q[r]==x的话,r就是我们找的靠右侧的数的位置

例题:

【洛谷】P1102 A-B 数对

A-B 数对

题目背景

出题是一件痛苦的事情!

相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!

题目描述

给出一串正整数数列以及一个正整数 C C C,要求计算出所有满足 A − B = C A - B = C A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式

输入共两行。

第一行,两个正整数 N , C N,C N,C。

第二行, N N N 个正整数,作为要求处理的那串数。

输出格式

一行,表示该串正整数中包含的满足 A − B = C A - B = C A−B=C 的数对的个数。

样例 #1

样例输入 #1

4 1
1 1 2 3

样例输出 #1

3

提示

对于 75 % 75\% 75% 的数据, 1 ≤ N ≤ 2000 1 \leq N \leq 2000 1≤N≤2000。

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 2 × 1 0 5 1 \leq N \leq 2 \times 10^5 1≤N≤2×105, 0 ≤ a i < 2 30 0 \leq a_i <2^{30} 0≤ai<230, 1 ≤ C < 2 30 1 \leq C < 2^{30} 1≤C<230。

2017/4/29 新添数据两组

思路:

这题先走了个弯路,即排序后,先打算固定一个数,然后看后面的数减去前面的数,如果等于c,则记一次数,然而这种方法就是常说的暴力法,数据量大的时候会超时,我们的计算机1s内能算1e7次到1e8次,超过这个数必然超时了

因此正解是利用二分,先移项,A=B+C,C是固定的,那么我们去遍历数组,数组的每一项都在每一次循环作为B,然后加上C的得到数A,然后在去数组中寻找A的位置,找到1个加入答案,没找到就不加,注意二分一定要先排序排序排序,还有就是我们在数据范围很大的时候一定要开long long ,如果判断不准,那就开着long long

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL sum=0;
LL bserach1(LL q[],LL n,LL a)
{
   LL l=0,r=n-1;
   LL mid=l+r>>1;
   
   while(l<=r)
   {
       mid=l+r>>1;
       if(q[mid]>=a){r=mid-1;}
       else l=mid+1;
   }
   if(q[l]==a)return l;
   else return -1;
}
LL bserach2(LL q[],LL n,LL a)
{
   LL l=0,r=n-1;
   LL mid=l+r>>1;

   while(l<=r)
   {
       mid=l+r>>1;
       if(q[mid]<=a){l=mid+1;}
       else r=mid-1;
   }
   if(q[r]==a)return r;
   else return -1;
}
int main()
{
    LL n=0,c=0;LL q[1000000]={0};
    cin>>n>>c;
    for(LL i=0;i<n;i++)cin>>q[i];
    sort(q,q+n);
    LL res1=0,res2=0;
    for(LL i=0;i<n;i++)
    {   
        LL a=q[i]+c;
        res1=bserach1(q,n,a);
        if(res1==-1)continue;
        else
        {
         res2=bserach2(q,n,a);
        }
        sum+=(res2-res1+1);
    }
    cout<<sum;
    return 0;
}

交完后发现#4 RE了,一直不知道为什么,后来问了学长才知道是初始化的原因。

RE的错误点一般是在和溢出有关,数组溢出,还有就是未初始化,未初始化这个数可能会很大,导致溢出

所以注意一定要初始化!!!初始化!!!初始化!!!

[蓝桥杯 2023 省 B] 冶炼金属

[蓝桥杯 2023 省 B] 冶炼金属

题目描述

小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V V V, V V V 是一个正整数,这意味着消耗 V V V 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V V V 时,无法继续冶炼。

现在给出了 N N N 条冶炼记录,每条记录中包含两个整数 A A A 和 B B B,这表示本次投入了 A A A 个普通金属 O,最终冶炼出了 B B B 个特殊金属 X。每条记录都是独立的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。

根据这 N N N 条冶炼记录,请你推测出转换率 V V V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。

输入格式

第一行一个整数 N N N,表示冶炼记录的数目。

接下来输入 N N N 行,每行两个整数 A , B A,B A,B,含义如题目所述。

输出格式

输出两个整数,分别表示 V V V 可能的最小值和最大值,中间用空格分开。

样例 #1

样例输入 #1

3
75 3
53 2
59 2

样例输出 #1

20 25

提示

【样例说明】

当 V = 20 V=20 V=20 时,有: ⌊ 75 20 ⌋ = 3 , ⌊ 53 20 ⌋ = 2 , ⌊ 59 20 ⌋ = 2 \left\lfloor\frac{75}{20}\right\rfloor=3,\left\lfloor\frac{53}{20}\right\rfloor=2,\left\lfloor\frac{59}{20}\right\rfloor=2 ⌊2075⌋=3,⌊2053⌋=2,⌊2059⌋=2,可以看到符合所有冶炼记录。

当 V = 25 V=25 V=25 时,有: ⌊ 75 25 ⌋ = 3 , ⌊ 53 25 ⌋ = 2 , ⌊ 59 25 ⌋ = 2 \left\lfloor\frac{75}{25}\right\rfloor=3,\left\lfloor\frac{53}{25}\right\rfloor=2,\left\lfloor\frac{59}{25}\right\rfloor=2 ⌊2575⌋=3,⌊2553⌋=2,⌊2559⌋=2,可以看到符合所有冶炼记录。

且再也找不到比 20 20 20 更小或者比 25 25 25 更大的符合条件的 V V V 值了。

【评测用例规模与约定】

对于 30 % 30 \% 30% 的评测用例, 1 ≤ N ≤ 1 0 2 1 \leq N \leq 10^{2} 1≤N≤102。

对于 60 % 60 \% 60% 的评测用例, 1 ≤ N ≤ 1 0 3 1 \leq N \leq 10^{3} 1≤N≤103。

对于 100 % 100 \% 100% 的评测用例, 1 ≤ N ≤ 1 0 4 1 \leq N \leq 10^{4} 1≤N≤104, 1 ≤ B ≤ A ≤ 1 0 9 1 \leq B \leq A \leq 10^{9} 1≤B≤A≤109。

蓝桥杯 2023 省赛 B 组 C 题。

==思路:==这题用二分是可行的,用两次二分,一次寻找靠左边的数,即我们的vmin,另一次则寻找靠右边的数,即我们的vmax

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
int n;
int a[N], b[N];
bool check1(int v)
{
    for (int i = 0; i < n; i++)
    {
        if (a[i] / v > b[i])return false;
    }
    return true;
}
bool check2(int v)
{
    for (int i = 0; i < n; i++)
    {
        if (a[i] / v < b[i])return false;
    }
    return true;
}
int main()
{
    
    cin >> n;
    for (int i = 0; i < n; i++)cin >> a[i] >> b[i];
    int l = 0, r = 1e9, vmin = 0, vmax = 0;
    while (l <= r)
    {
        int mid = l + ((r - l) >> 1);
        if (check1(mid)) { vmin = mid; r = mid - 1; }
        else l = mid + 1;
    }
    l = 1, r = 1e9;
    while (l <= r)
    {
        int mid = l + ((r - l) >> 1);
        if (check2(mid)) { vmax = mid; l = mid + 1; }
        else r = mid - 1;
    }
    cout << vmin<< " " << vmax;
    return 0;
}
相关推荐
no_play_no_games15 分钟前
[模板]树的最长路径
算法·深度优先·图论·树形结构
tan77º42 分钟前
【C++】异常
c++·算法
ymchuangke1 小时前
数据清洗-缺失值处理-缺失值可视化图(竖线)
python·算法·数学建模
我要学编程(ಥ_ಥ)1 小时前
滑动窗口算法专题(1)
java·数据结构·算法·leetcode
niceffking1 小时前
JVM 一个对象是否已经死亡?
java·jvm·算法
大油头儿1 小时前
排序算法-冒泡排序
数据结构·算法·排序算法
地平线开发者2 小时前
地平线占用预测 FlashOcc 参考算法-V1.0
算法·自动驾驶
LluckyYH2 小时前
代码随想录Day 46|动态规划完结,leetcode题目:647. 回文子串、516.最长回文子序列
数据结构·人工智能·算法·leetcode·动态规划
源代码:趴菜2 小时前
LeetCode118:杨辉三角
算法·leetcode·动态规划
luluvx2 小时前
LeetCode[中等] 74.搜索二维矩阵
算法·leetcode·矩阵