【二分搜索法 C/C++】洛谷P1102 A-B 数对

2025 - 02 - 13 - 第 52 篇
作者(Author): 郑龙浩 / 仟墨(CSND)
【二分搜索】

洛谷P1102 A-B 数对

题目背景

出题是一件痛苦的事情!

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

题目描述

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

输入格式

输入共两行。

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

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

输出格式

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

输入输出样例 #1

输入 #1

4 1
1 1 2 3

输出 #1

3

说明/提示

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

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

2017/4/29 新添数据两组、

思路

**DeepSeek 根据我代码,整理的思路:**懒得写思路整理了

好的!下面我将从 问题分析代码思路实现细节示例运行 四个方面,清晰地解释这个代码的逻辑,帮助你更好地理解和记笔记。


1. 题目分析

  • 直接暴力枚举所有数对 A A A B B B,检查是否满足 A − B = C A - B = C AB=C,时间复杂度为 O ( N 2 ) O(N^2) O(N2),对于 N = 2 × 1 0 5 N = 2 \times 10^5 N=2×105 的数据规模来说,这种方法会超时。
  • 需要一种更高效的方法来解决这个问题。

2. 代码思路

2.1 转化问题

A − B = C A - B = C AB=C 转化为 A = B + C A = B + C A=B+C,即在数组中寻找满足 A = B + C A = B + C A=B+C 的元素对。

2.2 核心思想

  • 对于数组中的每一个元素 B B B,计算 A = B + C A = B + C A=B+C
  • 统计数组中等于 A A A 的元素个数,这些元素都可以与 B B B 组成满足 A − B = C A - B = C AB=C 的数对。

2.3 实现方法

  1. 排序:对数组进行排序,以便使用二分查找。
  2. 二分查找
    • 使用 lower_bound 找到第一个等于 A A A 的位置。
    • 使用 upper_bound 找到第一个大于 A A A 的位置。
    • 两者之间的差值就是等于 A A A 的元素个数。
  3. 累加结果:将所有满足条件的数对个数累加到 ans 中。

3. 代码实现细节

3.1 输入处理

long long N, C; // 数组长度 和 差值 C
cin >> N >> C; // 输入数组长度和差值 C
vector<long long> arr(N); // 存储输入的所有数字
for (auto i = arr.begin(); i < arr.end(); i++) {
    cin >> *i; // 输入数组元素
}
  • 使用 vector<long long> 存储数组元素,支持动态大小。
  • 通过迭代器遍历数组并读取元素。

3.2 排序

sort(arr.begin(), arr.end()); // 对数组进行排序
  • 对数组进行升序排序,以便后续使用二分查找。

3.3 遍历数组并统计数对

long long ans = 0; // 存放满足 A - B = C 的数量
for (auto i = arr.begin(); i < arr.end(); i++) {
    auto first_space = lower_bound(arr.begin(), arr.end(), *i + C);
    auto last_space = upper_bound(arr.begin(), arr.end(), *i + C);
    ans += last_space - first_space;
}
  • lower_bound:找到第一个大于或等于 A = B + C A = B + C A=B+C 的位置。
  • upper_bound:找到第一个大于 A = B + C A = B + C A=B+C 的位置。
  • last_space - first_space:计算等于 A A A 的元素个数。
  • 将满足条件的数对个数累加到 ans 中。

3.4 输出结果

cout << ans; // 输出结果
  • 输出最终的数对个数。

4. 总结

1核心思想

  • A − B = C A - B = C AB=C 转化为 A = B + C A = B + C A=B+C,通过排序和二分查找高效解决问题。

2时间复杂度

  • 排序: O ( N log ⁡ N ) O(N \log N) O(NlogN)
  • 遍历数组 + 二分查找: O ( N log ⁡ N ) O(N \log N) O(NlogN)
  • 总时间复杂度: O ( N log ⁡ N ) O(N \log N) O(NlogN)

3空间复杂度

  • O ( N ) O(N) O(N),用于存储数组。

代码

// 洛谷P1102 A - B 数对
// 2025-02-12
// 郑龙浩 / 仟濹
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
using namespace std;
int main( void ){
    long long N, C; // 数组长度 差(被减数 - 减数 结果)
    cin >> N >> C; // 输入数组长度
    vector <long long> arr( N ); // 存储输入的所有数字
    for ( auto i = arr.begin(); i < arr.end(); i ++ ){
        cin >> *i;
    }
    sort ( arr.begin(), arr.end() );
    long long ans = 0; // 存放满足 A - B = C 的数量
    // 反过来判断,计算 B + C == A 的数量,也就是寻找A的数量
    for ( auto i = arr.begin(); i < arr.end(); i ++ ){
        // first_space - 第一个 B + C 
        // last_space - 最后一个 B + C
        // ans --> A 的数量 == B + C == A 的数量 == A - B 的数量
        auto first_space = lower_bound( arr.begin(), arr.end(), *i + C );
        auto last_space = upper_bound( arr.begin(), arr.end(), *i + C );
        ans += last_space - first_space;
    }
    cout << ans;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值