HDUOJ2141 Can you find it? 题解

原题链接

Description

Time Limit: 10000/3000 MS (Java/Others), Memory Limit: 32768/10000 K (Java/Others)

题目描述

给定三个数列 \(A,B,C\),再给一个数 \(X\)。请判断是否能找到三个数 \(A_i,B_j,C_k\),使得:\(A_i + B_j + C_k = X\)

输入描述

有多组测试数据。每组数据格式如下:

  • 第一行有三个整数 \(L,N,M\)
  • 第二行有 \(L\) 个整数,表示数列 \(A\)
  • 第三行有 \(N\) 个整数,表示数列 \(B\)
  • 第四行有 \(M\) 个整数,表示数列 \(C\)
  • 第五行有一个整数 \(S\),表示接下来有 \(S\) 个待判断的整数 \(X\)
  • 接下来 \(S\) 行,每行有一个整数 \(X\)

数据范围:\(1 \le L, N, M \le 500\)\(1 \le S \le 1000\)。所有整数均为 \(32\) 位整数。

输出描述

对每组数据,首先输出该组数据的编号,格式为 \(\texttt{Case d:}\),其中 \(d\)\(1\) 开始编号。
然后对于 \(S\) 个查询,每个查询如果存在满足条件的三个数,输出 \(\texttt{YES}\),否则输出 \(\texttt{NO}\)

Solution

时间限制和内存限制也是题干重要的一部分。题目的限制不同,我们就可能采用不同的算法。

如本题,最直接的想法自然是使用 unordered_set 记录所有 \(A_i\)\(B_j\) 的和,然后枚举 \(C_k\),检查哈希表中是否存在某个值等于 \(X-C_k\)。这样的做法时间复杂度是 \(O(LN+MS)\),似乎过本题绰绰有余。但是,unordered_set 存储一个元素的空间开销较大,约为 32 ~ 40 字节。这样一来,总内存很可能超过 10000KB,MLE。

于是,我们需要考虑用时间换空间:改用一般数组记录所有 \(A_i\)\(B_j\) 的和并排序,查询时对每个 \(C_k\)二分查找判断 \(X-C_k\) 是否存在。这样内存仅需约 3MB,完全满足限制。而时间复杂度只多乘了个 \(O(\log{LN})\),依然能轻松通过。

当然,手写哈希也是一种好办法。

Code

// 二分

#include <bits/stdc++.h>
typedef long long i64;
using namespace std;
const int MAX = 500;
int l, n, m;
i64 a[MAX + 5], b[MAX + 5], c[MAX + 5], t[MAX * MAX + 5];

int solve() {
    i64 x;
    scanf("%lld", &x);
    for (int i = 1; i <= m; ++i)
        if (*lower_bound(t + 1, t + l * n + 1, x - c[i]) == x - c[i])
            return printf("YES\n");
    return printf("NO\n");
}

int main() {
    int cnt = 0, s;
    while (~scanf("%d%d%d", &l, &n, &m)) {
        printf("Case %d:\n", ++cnt);

        for (int i = 1; i <= l; ++i)
            scanf("%lld", a + i);
        for (int i = 1; i <= n; ++i)
            scanf("%lld", b + i);
        for (int i = 1; i <= m; ++i)
            scanf("%lld", c + i);
        
        for (int i = 1; i <= l; ++i)
            for (int j = 1; j <= n; ++j)
                t[(i - 1) * n + j] = a[i] + b[j];
        
        sort(t + 1, t + l * n + 1);
        
        scanf("%d", &s);
        while (s--) solve();
    }
    return 0;
}
// 哈希

#include <bits/stdc++.h>
typedef long long i64;
using namespace std;
const int MAX = 500, P = 10007;
int l, n, m;
i64 a[MAX + 5], b[MAX + 5], c[MAX + 5];

vector<i64> h[P];

bool find(i64 val) {
    i64 pos = val % P;
    pos += pos < 0 ? P : 0;
    for (auto i : h[pos])
        if (i == val)
            return true;
    return false;
}

int solve() {
    i64 x;
    scanf("%lld", &x);
    for (int i = 1; i <= m; ++i)
        if (find(x - c[i]))
            return printf("YES\n");
    return printf("NO\n");
}

int main() {
    int cnt = 0, s;
    while (~scanf("%d%d%d", &l, &n, &m)) {
        printf("Case %d:\n", ++cnt);

        fill(h, h + P, vector<i64>());

        for (int i = 1; i <= l; ++i)
            scanf("%lld", a + i);
        for (int i = 1; i <= n; ++i)
            scanf("%lld", b + i);
        for (int i = 1; i <= m; ++i)
            scanf("%lld", c + i);

        for (int i = 1; i <= l; ++i)
            for (int j = 1; j <= n; ++j) {
                i64 pos = (a[i] + b[j]) % P;
                pos += pos < 0 ? P : 0;
                h[pos].push_back(a[i] + b[j]);
            }

        scanf("%d", &s);
        while (s--) solve();
    }
    return 0;
}
posted @ 2026-04-04 22:03  SHUddol  阅读(2)  评论(0)    收藏  举报