洛谷题解——P1102:A-B 数对

题目相关

题目链接

洛谷,https://www.luogu.com.cn/problem/P1102

我的OJ,http://47.110.135.197/problem.php?id=4759

题目描述

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

输入格式

输入共两行。

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

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

输出格式

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

输入样例

4 1
1 1 2 3

输出样例

3

数据规模

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

对于 100% 的数据,1 ≤ N ≤ 2×10^5。

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

题目分析

题意分析

在一个数列中,找出所有 A-B=C 的组合。

样例数据分析

有 4 个数据的数列,从中找出所有差值为 1 的数据组合。输入的数列为:1 1 2 3。我们可以知道:

1、第三个数据 2 减去第一个数据 1,两者之差为 1。

2、第三个数据 2 减去第二个数据 1,两者之差为 1。

3、第四个数据 3 减去第三个数据 2,两者之差为 1。

因此总计有 3 组数据。

数据规模分析

1、根据题目描述,保证所有输入数据都在 32 位带符号整数范围内,因此用 int 可以表示。

2、N 的最大范围是 2e5。这个有什么用?只有当数据 A 的总个数和数据 B 的总个数只差为 1 的时候,答案是最大的。就是我们如果有这样一组输入数据:

10 1
1 1 1 1 1 2 2 2 2 2

如果上面的数据,有 5 个 1、5 个 2,这样最后的答案为 5*5=25。

也就是说,我们的输出结果最大的范围是 (n/2)*(n/2),也就是 10^5*10^5=10^10。

说明我们需要用 long long 或者 unsigned long long 来表示结果。

注意:在乘积的过程中,可能导致 int 溢出。

模拟算法

算法思路

1、读入数。

2、统计每个数出现的数量。

3、排序。

4、去重。

5、计算结果。

该算法的核心是如何对所有的数据个数进行统计。

方法一:采用数组来统计,数组的大小是 2^32 个。这个方法明显比较浪费。

方法二:使用 STL 中的 map 来统计。

AC 参考代码

/*
OJ:MYOJ
题号:4759
题目:A-B 数对
地址:http://47.110.135.197/problem.php?id=4759
*/
#include <bits/stdc++.h>

const int MAXN = 2e5+2;
int arr[MAXN];

int main() {
    std::map<int, int> myMap;
    int n;
    int c;
    scanf("%d %d", &n, &c);

    int i;
    for (i=0; i<n; i++) {
        scanf("%d", &arr[i]);
        myMap[arr[i]]++;//当前数的个数++
    }
	
    std::sort(arr, arr+n);//排序
    n = std::unique(arr, arr + n) - arr;//去重

    //统计
    unsigned long long ans = 0;
    for (i=0; i<n; i++) {
        if ((myMap[arr[i]] && myMap[arr[i]-c])) {
            ans += ((unsigned long long)myMap[arr[i]] * myMap[arr[i]-c]);
        }
    }
    printf("%llu\n", ans);

    return 0;
}

细节讲解

1、我们必须排序。因为题目没有告诉我们数据是有序的。

2、通过统计个数后,重复的元素就可以删除了。

3、注意计算 ans 的时候,先要将 int 的数据类型强制转换为 unsigned long long,否则两个 int 乘法可能导致溢出。比如输入有 2e5个数据,C 为 1,数列中有 1e5 个 1 和 1e5 个 2。这样我们的答案是 10^5*10^5=10*10,而样例代码中的 map 中保存的是 int 类型,将导致数据溢出。

二分查找

算法思路

1、读入数。

2、排序。

3、从头开始二分查找。我们有了 A 和 C,就可以在数列中查有几个 B。也就是查找数据 B 的左下界和右上界。

AC 参考代码

/*
OJ:MYOJ
题号:4759
题目:A-B 数对
地址:http://47.110.135.197/problem.php?id=4759
*/
#include <bits/stdc++.h>

const int MAXN = 2e5+2;
int arr[MAXN];

int main() {
    int n;
    int c;
    scanf("%d %d", &n, &c);

    int i;
    for (i=0; i<n; i++) {
        scanf("%d", &arr[i]);
    }
	
    std::sort(arr, arr+n);//排序

    //统计
    unsigned long long ans = 0;
    for (i=0; i<n; i++) {
        int b = arr[i]-c;
        int lo = std::lower_bound(arr, arr+n, b) - arr;
        int hi = std::upper_bound(arr, arr+n, b) - arr;
        if (lo!=hi || arr[lo]==b) {
            ans += (hi-lo);
        }
    }
    printf("%llu\n", ans);

    return 0;
}

 

洛谷是一个广受欢迎的在线编程学习平台,它提供了大量的编程题目,特别是针对NOIP(全国青少年信息学奥林匹克)普及组的比赛训练。对于初学者来说,掌握这些例题的Python实现是提高编程能力的重要途径。以下是一些典型的洛谷普及组例题及其Python实现。 --- ### P1001 A+B Problem 题目要求输入两个整 `a` 和 `b`,输出它们的和。 ```python a, b = map(int, input().split()) print(a + b) ``` --- ### P1075 质因分解 题目要求将一个正整分解为质因的乘积形式。 ```python n = int(input()) i = 2 while i * i <= n: while n % i == 0: print(i) n //= i i += 1 if n > 1: print(n) ``` --- ### P1914 小书童——凯撒密码 题目要求实现凯撒密码的加密过程,即将每个字母按照给定的偏移量进行移位。 ```python s = input().strip() k = int(input()) result = '' for c in s: if 'a' <= c <= 'z': result += chr((ord(c) - ord('a') + k) % 26 + ord('a')) elif 'A' <= c <= 'Z': result += chr((ord(c) - ord('A') + k) % 26 + ord('A')) else: result += c print(result) ``` --- ### P1028 的计算 题目要求计算满足条件的量,可以通过递归或动态规划来实现。 ```python n = int(input()) dp = [0] * (n + 1) def count(x): if dp[x] != 0: return dp[x] res = 1 for i in range(1, x // 2 + 1): res += count(i) dp[x] = res return res print(count(n)) ``` --- ### P1035 级求和 题目要求计算级 `1 + 1/2 + 1/3 + ... + 1/n` 的前 `n` 项和,直到和大于等于 `k`。 ```python k = int(input()) s = 0.0 n = 0 while s < k: n += 1 s += 1.0 / n print(n) ``` --- ### P1423 小玉在游泳 题目要求计算小玉游过 `n` 米所需的最少时间。 ```python n = float(input()) speed = 2.0 time = 0 while speed <= n: n -= speed speed *= 0.98 time += 1 time += n / speed print(int(time) + (1 if time - int(time) > 0 else 0)) ``` --- ### P1307 字反转 题目要求将一个整反转输出。 ```python n = input().strip() if n[0] == '-': print('-' + n[:0:-1].lstrip('0')) else: print(n[::-1].lstrip('0')) ``` --- ### P1980 计算器的改良 题目要求解析一个简单的计算器表达式并输出结果。 ```python expr = input().strip() result = eval(expr) print(result) ``` --- ### P1085 不高兴的津津 题目要求找出津津一周中最不高兴的一天。 ```python max_val = 0 day = 0 for i in range(1, 8): a, b = map(int, input().split()) total = a + b if total > max_val: max_val = total day = i print(day) ``` --- ### P1427 小鱼的字游戏 题目要求将输入的字逆序输出。 ```python nums = list(map(int, input().split())) nums.pop() for num in reversed(nums): print(num, end=' ') ``` --- 以上是部分洛谷普及组例题的Python实现。这些题目涵盖了顺序结构、循环结构、字符串处理、递归与动态规划等多个方面,适合初学者逐步掌握编程技巧。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力的老周

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

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

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

打赏作者

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

抵扣说明:

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

余额充值