一本通题解——1244:和为给定数

题目相关

题目链接

一本通 OJ,http://ybt.ssoier.cn:8088/problem_show.php?pid=1244

计蒜客 OJ,https://nanti.jisuanke.com/t/T1158

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

题目描述

给出若干个整数,询问其中是否有一对数的和等于给定的数。

输入

共三行:

第一行是整数 n,表示有 n 个整数。

第二行是 n 个整数。整数的范围是在 0 到 2×10^8 之间。

第三行是一个整数 m,表示需要得到的和。

输出

若存在和为 m 的数对,输出两个整数,小的在前,大的在后,中间用单个空格隔开。若有多个数对满足条件,选择数对中较小的数更小的。若找不到符合要求的数对,输出一行"No"

样例输入

4
2 5 1 4
6

样例输出

1 5

数据范围

0 < n ≤ 100,000

0 ≤ m ≤ 2^30

题目分析

题意

在一个数列中找,是否存在两个数,这两个数的和是 m。若有多个数对满足条件,选择数对中较小的数更小的。若找不到符合要求的数对,输出一行"No"

数据范围分析

n 的最大值是 100,000,也就是说,我们设计的算法时间复杂度不能超过 O(nlogn),否则就是 TLE。

数列中最大的数可能是 2×10^8,也就是说可以用 int 来表示。m 的最大值是 2^30,也就是说需要用 unsigned long long 来表示。因此本题的数据统一用 unsigned long long 表示。

样例数据分析

根据题目,输入的数列为 [2 5 1 4],m 为 6。我们知道数列中的 2+4=6,5+1=6。根据要求,输出较小的数,所以输出 1 5。

算法设计

由于算法的时间复杂度不能超过 O(nlogn),暴力肯定是 TLE 的。同时要求输出较小的数,那么我们进行一下排序,将较小的数放在前面,这样满足条件的第一个答案,自然是较小的数。

1、读入所有的数据,并保存。

2、排序数组。

3、遍历数组每一个元素 a[i],检查 a[i] 是否是答案。如果 m 大于等于 a[i],同时 m-a[i] 存在于本数组中,那么数对 a[i] 和 m-a[i] 就是答案。如果 m 小于 a[i],说明没有答案,输出 No,因为数组里的数取值范围为 [0, 2*10^8]。

为了降低时间复杂度,查找 m-a[i] 是否在数组中,我们使用二分查找。这样,这个算法的 f(n)=n*logn+n*logn,对应的时间复杂度为 O(nlogn),满足我们的需求。

AC 参考代码

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ULL;

const int MAXN = 1e5+6;
ULL a[MAXN] = {};
int n;

int main() {
    //读入数据
    scanf("%d", &n);
    for (int i=0; i<n; i++) {
        scanf("%lld", &a[i]);
    }
    ULL m;
    scanf("%lld", &m);

    //排序
    sort(a, a+n);

    //数据处理
    for (int i=0; i<n; i++) {
        if (m>=a[i]) {
            //注意:a[i]可能为0
            if (binary_search(a, a+n, m-a[i])) {
                printf("%lld %lld\n", a[i], m-a[i]);
                return 0;
            }
        } else {
            break;
        }
    }

    printf("No\n");

    return 0;
}
发布了203 篇原创文章 · 获赞 101 · 访问量 104万+

猜你喜欢

转载自blog.csdn.net/justidle/article/details/104623127