Trouble
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3854 Accepted Submission(s): 1222Problem DescriptionHassan 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?
InputFirst 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.
OutputFor 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
221 -11 -11 -11 -11 -131 2 3-1 -2 -34 5 6-1 3 2-4 -10 -1
Sample Output
NoYes
Source2012 Multi-University Training Contest 4
思路:合并a[0]、a[1],a[2]、a[3],得到三個數組a[4]、s1[ ]、s2[ ],對a[4]枚舉,然後線上性時間內算出是否存在i、j,使得s1[i]+s2[j]+a[k]=0。線性演算法如下:將s1[ ]、s2[ ]排序,用兩個變數p1,p2分別表示訪問到s1[ ]、s2[ ]的位置,p1從前往後,p2從後往前。如果a[k]+s1[p1]+s2[p2]>0,則p2往後移,因為此時可以得出p2與其他的p1匹配都只會使三個數的和變大,所以p2沒有必要與其他的p1匹配後算了,同理可得a[k]+s1[p1]+s2[p2]<0的情況。
舉一反三:這個演算法可以解決這種類型的問題:給你三個數組,從三個數組中任選一個數,判斷這三個數的和是否能為一個值。
代碼:
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#define maxn 205#define maxx 40005using namespace std;int n,m,ans,cxx0,cxx1,cxx2;long long a[5][maxn];long long s1[maxx],s2[maxx];long long xx[maxx],yy[maxx],zz[maxn];void solve() // 合并a[0]、a[1],a[2]、a[3] 將相同的去掉 剪枝{ int i,j,cnt; for(i=0;i<5;i++) { sort(a[i],a[i]+n); } cnt=-1; for(i=0;i<n;i++) { for(j=0;j<n;j++) { cnt++; s1[cnt]=a[0][i]+a[1][j]; s2[cnt]=a[2][i]+a[3][j]; } } zz[0]=a[4][0]; cxx0=0; for(i=1;i<n;i++) { if(a[4][i]!=a[4][i-1]) { cxx0++; zz[cxx0]=a[4][i]; } } sort(s1,s1+cnt+1); xx[0]=s1[0]; cxx1=0; for(i=1;i<=cnt;i++) { if(s1[i]!=s1[i-1]) { cxx1++; xx[cxx1]=s1[i]; } } sort(s2,s2+cnt+1); yy[0]=s2[0]; cxx2=0; for(i=1;i<=cnt;i++) { if(s2[i]!=s2[i-1]) { cxx2++; yy[cxx2]=s2[i]; } }}bool isok(){ int i,j,k; long long nz; for(k=0;k<=cxx0;k++) // 對a[4]枚舉 { nz=zz[k]; for(i=0,j=cxx2;i<=cxx1||j>=0;) // 線性時間判斷是否存在a+b+c=0 { if(nz+xx[i]+yy[j]>0) { if(j>0) j--; else break ; } else if(nz+xx[i]+yy[j]<0) { if(i<cxx1) i++; else break ; } else return true ; } } return false ;}int main(){ int i,j,t; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i=0;i<5;i++) { for(j=0;j<n;j++) { scanf("%I64d",&a[i][j]); } } solve(); if(isok()) printf("Yes\n"); else printf("No\n"); } return 0;}