其他分享
首页 > 其他分享> > [luogu p1102] A-B 数对

[luogu p1102] A-B 数对

作者:互联网

传送门

A-B 数对

题目描述

出题是一件痛苦的事情!

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

好吧,题目是这样的:给出一串数以及一个数字 \(C\),要求计算出所有 \(A - B = C\) 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入输出格式

输入格式

输入共两行。

第一行,两个整数 \(N, C\)。

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

输出格式

一行,表示该串数中包含的满足 \(A - B = C\) 的数对的个数。

输入输出样例

输入样例 #1

4 1
1 1 2 3

输出样例 #1

3

说明

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

对于 \(100\%\) 的数据,\(1 \leq N \leq 2 \times 10^5\)。

保证所有输入数据都在 \(32\) 位带符号整数范围内。

2017/4/29 新添数据两组

分析

这道题是我在二分题单里遇到的,但是这道题的思路我死活想不到二分……

我的思路是这样的,首先把数排序一遍,然后如果A和C都确定了,那么B也只能是那个数。题目中说

不同位置的数字一样的数对算不同的数对

所以每一次扫到一个A,后面每一个B都是一种方案,也就是说方案数多了 B的个数 种。

思路也就很明显了,

思考到这里我终于明白为什么这道题在二分题单里了。我们来看最后一条:

方案数加上B的个数

这个B的个数怎么求呢?自然有一种方案是从头到尾扫一遍,不过这样的复杂度是\(\operatorname{O}(N)\),外层循环也是\(\operatorname{O}(N)\),整体的复杂度就是\(\operatorname{O}(N^2)\)了。然而数据范围是\(1 \le N \le 2 \times 10^5\)。\(\operatorname{O}(N^2)\)的复杂度显然不行。

那怎么办呢?

这个时候二分就要出场了。

不要忘记了数是排序的,也就是说数字为B的数在这个序列中是连续的。那么我们只要算出这个序列的头和尾就能算出数字为B的个数。

算出一个连续为B序列的头和尾,这就是裸到不能再裸的二分了。

那么是手写二分还是STL呢?这里就根据你的习惯来了。这里我选择STL,也就是lower_bound和upper_bound。

思路理明白,代码就简单了。

代码

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2020-06-13 10:29:10 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2020-06-13 10:53:14
 */
#include <iostream>
#include <cstdio>
#include <algorithm>

inline long read() {
    long x;
    std :: cin >> x;
    return x;
}

const int maxn = 200005;

long a[maxn];

int main() {
    long n = read(), c = read(), ans = 0;
    for (int i = 1; i <= n; ++i) a[i] = read();
    std :: sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; ++i) 
        ans += (std :: upper_bound(a + 1, a + n + 1, a[i] + c) - a) - (std :: lower_bound(a + 1, a + n + 1, a[i] + c) - a);
    std :: cout << ans << std :: endl;
    return 0;
}

评测记录

评测记录

标签:二分,10,p1102,luogu,数对,个数,long,leq,operatorname
来源: https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p1102.html