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;
}

  

 

posted @ 2014-11-22 19:47  chenjunjie1994  阅读(153)  评论(0编辑  收藏  举报