Trouble
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6911 Accepted Submission(s): 1927
Problem Description
Hassan is in trouble. His mathematics teacher has given him a very difficult problem called 5-sum. Please help him.
The 5-sum problem is defined as follows: Given 5 sets S_1,...,S_5 of n integer numbers each, is there a_1 in S_1,...,a_5 in S_5 such that a_1+...+a_5=0?
Input
First line of input contains a single integer N (1≤N≤50). N test-cases follow. First line of each test-case contains a single integer n (1<=n<=200). 5 lines follow each containing n integer numbers in range [-10^15, 1 0^15]. I-th line denotes set S_i for 1<=i<=5.
Output
For each test-case output "Yes" (without quotes) if there are a_1 in S_1,...,a_5 in S_5 such that a_1+...+a_5=0, otherwise output "No".
Sample Input
2 2 1 -1 1 -1 1 -1 1 -1 1 -1 3 1 2 3 -1 -2 -3 4 5 6 -1 3 2 -4 -10 -1
Sample Output
No Yes
Source
2012 Multi-University Training Contest 4
之前见过一道类似的题目,但是那题只有三个集合,当时用的是二分,将两个数组a, b相加组成一个新的数组A,之后再在A上二分找能够和c中的数符合条件的值。这题也类似,a,b相加组成s1,c,d组成s2,然后将其中一个排序,比如对s1排序,然后用二重循环再对s2和d中的数组合,再去s1中二分查找能够满足要求的数。复杂度O(n^3*logn),题目时间要求不高,能过。
还有一种解法是利用贪心。先利用分治思想,处理前两个集合的和s1,3 4集合的和s2。然后要介绍一种尺取法(也就是一种贪心思想):如何快速判断是否有A[i]+B[j]=x,先将A,B送小到大排序得到有序序列,可以先让i指向A数组的首指针,j指向B数组的为指针,判断A[i]+B[j]与x的大小关系,若A[i]+B[j]>x则j–;若A[i]+B[j]< x则i++。这样就可以在线性时间内判断是否A[i]+B[j]=x。最后复杂度是O(n^3)
#include <cstdio>
#include <algorithm>
#define ll long long
const int Max1 = 205, Max2 = 40005;
ll S1[Max1], S2[Max1], S3[Max1], S4[Max1], S5[Max1], SS1[Max2], SS2[Max2];
int N, n;
bool binarySearch(int i, int h)
{
int l = 0, mid;
while(l <= h)
{
mid = (l + h)>>1;
if(SS2[mid] == i) return true;
else if(SS2[mid] < i) l = mid + 1;
else h = mid - 1;
}
return false;
}
int main()
{
scanf("%d", &N);
while(N--)
{
scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%lld", S1+i);
for(int i = 0; i < n; i++) scanf("%lld", S2+i);
for(int i = 0; i < n; i++) scanf("%lld", S3+i);
for(int i = 0; i < n; i++) scanf("%lld", S4+i);
for(int i = 0; i < n; i++) scanf("%lld", S5+i);
int cnt = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) SS1[cnt++] = S1[i] + S2[j];
cnt = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) SS2[cnt++] = S3[i] + S4[j];
std::sort(SS2, SS2 + cnt);
bool flag = false;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < cnt; j++)
{
int left = 0 - S5[i] - SS2[j];
if(binarySearch(left, cnt))
{
flag = true;
break;
}
}
if(flag) break;
}
printf("%s\n", flag ? "Yes" : "No");
}
return 0;
}
第二种
#include <cstdio>
#include <algorithm>
#define ll long long
const int Max1 = 205, Max2 = Max1 * Max1;
ll S[5][Max1], SS1[Max2], SS2[Max2];
int N, n;
int main()
{
scanf("%d", &N);
while(N--)
{
scanf("%d", &n);
for(int i = 0; i < 5; i++)
for(int j = 0; j < n; j++) scanf("%lld", &S[i][j]);
int cnt = 0;
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
SS1[cnt] = S[0][i] + S[1][j];
SS2[cnt++] = S[2][i] + S[3][j];
}
}
std::sort(SS1, SS1 + cnt);
std::sort(SS2, SS2 + cnt);
bool flag = false;
for(int i = 0; i < n && !flag; i++)
{
int j = 0, k = cnt - 1;
ll s, x = 0 - S[4][i]; // 忘了定义为ll,WA N次
while(j < cnt && k >= 0)
{
s = SS1[j] + SS2[k];
if(s == x)
{
flag = true;
break;
}
else if(s < x) j++;
else k--;
}
}
printf("%s\n", flag ? "Yes" : "No");
}
return 0;
}