HDU 4334 Contest 4
本来以为是一道水题,好吧,做了才知道,出题的人有多牛。二分搜索是不可能的了,因为会超内存。。。
看到别人的搜索两个集合的提示,我就自己一边去想了。终于想出来了:
可以这样做,先把每两个集合的和值枚举出来并成一个大集合,排序,去重。剩下一个集合,于是,共三个集合。
枚举小的那个集合的元素,搜索两个大的集合。可以这样做,定义一个初始为指向最小元素的指针,一个指向最大元素的指针(两个指针是指向不同的集合的),两者之和相等则返回,小于则移动小指针+1,否则移动大指针-1.直至二者相等退出。然后再用两个指针交换指向另一个集合,重复上述过程。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define LL __int64 using namespace std; LL A[41000],B[41000]; LL C[41000]; int pa,pb; LL S[5][250]; bool find_t(LL a){ int tma,tmi; LL tmp; tma=pa,tmi=1; while(tma>=1&&tmi<=tma&&tmi<=pb){ tmp=A[tma]+B[tmi]; if(tmp==a) return true; else if(tmp<a) tmi++; else tma--; } tma=pb,tmi=1; while(tma>=1&&tmi<=tma&&tmi<=pa){ tmp=A[tmi]+B[tma]; if(tmp==a) return true; else if(tmp<a) tmi++; else tma--; } return false; } bool cmp(LL a,LL b){ if(a<b) return true; return false; } int main(){ int T,n; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=0;i<5;i++){ for(int j=1;j<=n;j++) scanf("%I64d",&S[i][j]); } pa=pb=0; C[0]=A[0]=B[0]=0; int tb=0; for(int i=0;i<=1;i++){ pb=0; for(int j=1;j<=n;j++){ if(tb==0) C[++pb]=C[0]+S[i][j]; else{ for(int k=1;k<=tb;k++) B[++pb]=C[k]+S[i][j]; } } if(tb==0) tb=n; else tb=tb*n; } tb=0; for(int i=2;i<4;i++){ pa=0; for(int j=1;j<=n;j++){ if(tb==0) C[++pa]=C[0]+S[i][j]; else{ for(int k=1;k<=tb;k++) A[++pa]=C[k]+S[i][j]; } } if(tb==0) tb=n; else tb=tb*n; } int t=1; sort(A+1,A+pa+1,cmp); for(int i=2;i<=pa;i++) if(A[i]!=A[t]){ A[++t]=A[i]; } pa=t; t=1; sort(B+1,B+pb+1,cmp); for(int i=2;i<=pb;i++) if(B[i]!=B[t]){ B[++t]=B[i]; } pb=t; bool flag=false; for(int j=1;j<n;j++){ if(find_t(-S[4][j])){ flag=true; break; } } if(flag) printf("Yes\n"); else printf("No\n"); } return 0; }