Trouble
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3784 Accepted Submission(s): 1187
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
题目大意:给你五个堆,在每一个堆里面找一个数据,如果能使得五个数相加为0输出yes否则输出no
解题思路:枚举五个堆就算加一个二分查找肯定会超时,这需要用到一个分治的思想,这里枚举超时主要原因就是可能会有和相等的待会儿又会算。可以先把前两堆的和存起来,相等的只存一个。这样把1,2堆放在p1中,3,4堆放在p2中。最后直接枚举第五堆,加两个指针,一个指向最小的,一个指向最大的,然后移动。这样只会移动2*(4*10^4)次,再*2*10^2,就不会超时。(思路来源于ice_crazy)
题目地址:Trouble
AC代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
__int64 a[4][205],p1[40005],p2[40005],b[205];
//b是第五堆,a前四堆
int t1,t2,n; //p1,p2中的脚标
//如果要把p1和p2也合并的话,需要10^10的内存,存不下,所以到这里只能枚举
void cal1() //第1堆与第2堆合并
{
int i,j,k=0;
__int64 tmp[40005];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
tmp[k++]=a[0][i]+a[1][j];
sort(tmp,tmp+k);
t1=-1; //p1中的脚标
p1[++t1]=tmp[0];
for(i=1;i<k;i++)
{
if(tmp[i]!=p1[t1])
p1[++t1]=tmp[i];
}
//t1++;
}
void cal2() //第3堆与第4堆合并
{
int i,j,k=0;
__int64 tmp[40005];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
tmp[k++]=a[2][i]+a[3][j];
sort(tmp,tmp+k);
t2=-1; //p2中的脚标
p2[++t2]=tmp[0];
for(i=1;i<k;i++)
{
if(tmp[i]!=p2[t2])
p2[++t2]=tmp[i];
}
//t2++;
}
int main()
{
int T,i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n); //每一堆有n个数据
for(i=0;i<4;i++)
for(j=0;j<n;j++)
scanf("%I64d",&a[i][j]);
for(i=0;i<n;i++)
scanf("%I64d",&b[i]);
cal1();
cal2();
int flag=0;
for(i=0;i<n;i++) //枚举第五堆
{
int s1=0,s2=t2; //s1,s2代表枚举时p1,p2的指针
while(s1<=t1&&t2>=0)
{
if(p1[s1]+p2[s2]+b[i]==0)
{
flag=1;
break;
}
if(p1[s1]+p2[s2]+b[i]<0) s1++;
else s2--;
}
if(flag) break;
}
if(flag) puts("Yes");
else puts("No");
}
return 0;
}