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;
}

浙公网安备 33010602011771号