2141 Can you find it?

来源:互联网 发布:法师升级数据 编辑:程序博客网 时间:2024/06/05 16:21

Can you find it?

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/10000 K (Java/Others)
Total Submission(s): 16968    Accepted Submission(s): 4318


Problem Description
Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.
 

Input
There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.
 

Output
For each case, firstly you have to print the case number as the form "Case d:", then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print "YES", otherwise print "NO".
 

Sample Input
3 3 31 2 31 2 31 2 331410
 

Sample Output
Case 1:NOYESNO

题意:

给你三个集合,每个集合中都有若干个元素,给出一个数,求能否从每个集合中找一个元素,使得他们的和为这个数!


分析:

第一个思路,最简单,那就是四层循环枚举,不用试了,我用血淋淋的事实告诉你,超时了....

第二个思路,还挺好,三层循环,中间加上比较复杂的判断,省了不少时间....不用试了,因为赤裸裸的真相就是..超时.......

抓狂

实在是超出大脑理解想象之外,还能有什么好方法,后来再想,可以用两个双循环,但是今天学了个好东西--二分查找,

然后学长介绍了这个题的很优化的方法,就不再想用两个单纯的双循环了!!!


最优思路:

一个一般的双层循环,外加 一个 双循环(外层是正常循环,内层是二分查找循环)........


解题思路:

给出了三个集合,每个都可能500多,如果把所有的可能性全部求出来放在一个数组里,那么就超内存了..500*500*500=???

所以一个折中的方法是,只把两个集合相加的所有情况存在一个数组里,相当于一个集合了,然后现在的问题就从三个集合求定值,转化为两个集合求定值了.......

两个元素求定值,完全可以用一个双循环来判断,但是用二分查找的方法,省了不少时间.....

具体解析看代码注释,思路大概就这些了......



#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int maxx[1000005],t=0;int main(){int i,j,k, x,y,z, n,m;int a[505],b[505],c[505],s;while(~scanf("%d%d%d",&x,&y,&z)){m=0;printf("Case %d:\n",++t);memset(maxx,0,sizeof(maxx));for(i=0;i<x;++i)//输入的格式我是醉了,搞了这么多循环.....{scanf("%d",a+i);}for(i=0;i<y;++i){scanf("%d",b+i);}for(i=0;i<z;++i){scanf("%d",c+i);}for(i=0;i<x;++i)//先把两个集合所有的可能结果保存下来{for(j=0;j<y;++j){maxx[m++]=a[i]+b[j];}}sort(maxx,maxx+m);//为了便于二分查找,就排排序...sort(c,c+z);//很多人的方法这里不需要排序,不过我有我的用处scanf("%d",&n);for(j=0;j<n;++j)//这里输出的格式我也是醉了,是每个输入之后立刻就输出一个结果,不是每组作为一个整体输出.....{int kase=0;//标记变量scanf("%d",&s);if((maxx[0]>s-c[0])||(maxx[m-1]<s-c[z-1]))//这就是我对集合 c 进行排序的用处,可能会省些时间{printf("NO\n");continue;}for(i=0;i<z&&(!kase);++i)//外层循环控制运算的是 c 集合的哪一个元素,进行遍历{int l=0,r=m-1,mid;while(l<=r&&(!kase))//二分查找.....{mid=(l+r)/2;if(maxx[mid]>s-c[i]){r=mid-1;}else if(maxx[mid]<s-c[i]){l=mid+1;}else{kase=1;//标记变量}}}if(kase)//控制输出{printf("YES\n");continue;}printf("NO\n");}}return 0;}


题说完了,扯一会自己的感想,刚开始的时候也是用了第二种方法,超时了,后来换用第三种方法,优化了很久,解决了超内存和超时的问题,但是结果一直错误........

做这一个题,做了好几个小时,就是纠结在纠错上,我把我的程序里的二分查找修改成一个子函数来调用,可以 ac ,但是修改回来,就一直错误,一直到后来,才发现一个隐秘的错误.....

按我的处理的方式时候会超出 int 范围!!就在那个最大值的数组和另外一个数组进行处理的时候上,然后我处理成了相减.......

ac了......

收获最大的一点就是,时刻注意自己处理的数据的范围!!!说不定什么时候就会被阴了.........





0 0