题目
三数和为零
Time Limit: 2 Sec
Memory Limit: 128 MB
Submit: 911
Solved: 72
[
Submit][
Status][
Web Board]
三数和为零
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 911 Solved: 72
[ Submit][ Status][ Web Board]
Description
在序列a
1,a
2,...,a
n(n>=3)中,是否存在(0<i<j<k<=n)满足a
i+a
j+a
k=0?
Input
多组数据,第一行给出数据组数T
每组数据第一行有一个整数n(3<=n<=2000),表示序列的长度
第二行有n个由空格隔开的整数,表示序列{a
n},(|a
i|<=10
9)
Output
对每组数据,若存在,输出Yes,否则输出No
Sample Input
2
3
1 2 3
3
-1 3 -2
Sample Output
No
Yes
思路
这题跟《挑战》上的最开始的抽签那题是一样的。。。只是那题是每个数可重复利用,这里不能重复利用,即无放回抽签。
思路为,枚举三个数(暴力)的复杂度为O(n^3),但我们稍微变形一下暴力的公式,变为只枚举两个数,看两数和的相反数是否在数列中,这里只需在枚举的同时判断是否有重复即可,复杂度为O(n^2)。
判重,若每次枚举都话O(n)的时间去判断是否重复的话,这个算法的复杂度还会是O(n^3)。可用数据结构存储,用空姐换时间。。。
代码#include <bits/stdc++.h>
using namespace std;
#define MAX_N 2010
int num[MAX_N];
int N;
void solve();
map<int, int> tMap;
int main()
{
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &N);
tMap.clear();
for (int i = 0; i < N; i++) {
scanf("%d", &num[i]);
tMap[num[i]]++;
}
solve();
}
return 0;
}
void solve() {
sort(num, num+N);
for (int a = 0; a < N; a++) {
for (int b = 0; b < N; b++) {
if (a == b) continue;
if (binary_search(num, num+N, -(num[a]+num[b]) ) ) {
if (-(num[a]+num[b]) == num[a] ) {
// if (count(num, num+N, num[a]) < 2) {
if (tMap[num[a]] < 2) {
puts("No");
return;
}
}
if (-(num[a]+num[b]) == num[b] ) {
if (tMap[num[b]] < 2) {
puts("No");
return;
}
}
puts("Yes");
return;
}
}
}
puts("No");
return;
}