!HDU 4334 集合各出一数和为0是否存在-思维、卡时间-(指针的妙用)

来源:互联网 发布:eclipse编译java文件 编辑:程序博客网 时间:2024/06/06 01:53

题意:有5个集合,集合的大小是n,每一个集合出一个数,问能不能找到五个数的和为0。数据范围:T<=50;n<=200

分析:

暴力枚举是n^5*T,超时,那么就要用一些技巧了。

这里有一个指针的妙用:如何在O(n)的复杂度找A,B,使得A+B==C(A,B分别属于一个数列a,b)。做法是先把a,b分别按升序排序,然后一个指针i指向a的首,指针j指向b的尾,判定指针指向的数的和是否==C,若等于则结束查找,若小于,则i++,若大于则 j- -,如果有一个指针已经走到了头还没找到A+B==C,则说明不存在这样的AB;

这个问题再变形:有三个数列a,b,c,如何在O(n^2)的复杂度找A,B,C,使得A+B==C。方法还是上面那个,就是多了一个遍历C的循环。

本题就是用了这个技巧,还用了一点分治的思想吧,其实不是分治,反正我就这样记了,就是说不要题目给的一个问题就想着把这个问题整体的解决,题目说求和,我们不是一定非要一步到位的求和啊,我们可以把求和这个问题分成:a1+a2;a3+a4;a5 求和就是(a1+a2)+(a3+a4)+a5,又因为是找等于0,所以就是:(a1+a2)+(a3+a4)==-a5,这样不就把问题转换成上面的模型了吗。

另外,排序+去重可以用set来做,set.insert()的时候会自动去重并且按升序排序。

代码:

#include<iostream>#include<set>#include<algorithm>using namespace std;set<long long> s1,s2;int t,n;long long a[6][300];long long sum[3][50000];int main(){cin>>t;while(t--){cin>>n;s1.clear();s2.clear();for(int i=0;i<5;i++){for(int j=0;j<n;j++){cin>>a[i][j];}}for(int i=0;i<n;i++){for(int j=0;j<n;j++){s1.insert(a[0][i]+a[1][j]);s2.insert(a[2][i]+a[3][j]);}}for(int i=0;i<n;i++) a[4][i]*=(-1);int len1=0,len2=0;set<long long>::iterator it;for(it=s1.begin();it!=s1.end();it++) sum[1][len1++]=(*it);for(it=s2.begin();it!=s2.end();it++) sum[2][len2++]=(*it);int ok1=0;for(int i=0;i<n;i++){int ok=1;int j=0,k=len2-1;while(sum[1][j]+sum[2][k]!=a[4][i]){if(sum[1][j]+sum[2][k]<a[4][i]) j++;else k--;if(j>=len1||k<0){ok=0;break;}}if(ok){ok1=1;break;}}if(ok1) cout<<"Yes"<<endl;else cout<<"No"<<endl;}}


0 0
原创粉丝点击