题目链接:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=577&pid=1002
题目大意:在n个数里面任选两个x,y找出里面gcd(x,y)最大的gcd值。
解析:由于n的范围是2到10w,所以暴力枚举肯定超时。
解法一:对于输入的n 个数依次求出他们的因子,将因子个数记录在ant[]数组内。我们容易知道,如果一个因子的个数超过2 的话,那么这个因子必为公因子。所以我们只需要寻找这些公因子里面最大的那个就可以了。详细代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #define max(x,y) x>y?x:y 5 using namespace std; 6 7 int ant[1000006]; 8 int a[1000006]; 9 int main() 10 { 11 int t; 12 scanf ("%d",&t); 13 for(int i=1;i<=t;i++) 14 { 15 int n,maxp=1; 16 memset(ant,0,sizeof(ant)); 17 scanf ("%d",&n); 18 for(int j=0;j<n;j++) 19 { 20 scanf ("%d",&a[j]); 21 for(int k=1;k<=a[j];k++)//计算n个数的因子,因子个数存放在ant[]数组内 22 { 23 if(a[j]%k==0) 24 ant[k]++; 25 } 26 maxp=max(maxp,a[j]); 27 } 28 int ans=1; 29 for(int j=1;j<=maxp;j++) 30 { 31 if(ant[j]>=2)//寻找公因子找到最大的那个公因子 32 ans=max(ans,j); 33 } 34 printf("Case #%d: %d ",i,ans); 35 } 36 return 0; 37 }
解法二:首先maxp是n个数里的最大数。那么这个最大公因子必然在1~maxp之间。那么我们可以直接在maxp~1之间枚举每个数k,判断在n个数里面是否有2个或者更多的k的倍数。一旦找到这样的数k,那么可以断定k就是答案。直接跳出循环。不需要执行以后的循环了,节约了大部分时间。代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 6 int ant[1000006],a[1000006]; 7 int main() 8 { 9 int t; 10 scanf ("%d",&t); 11 for(int i=1;i<=t;i++) 12 { 13 memset(ant,0,sizeof(ant)); 14 int maxp=1,n,j,k; 15 scanf ("%d",&n); 16 for(j=1;j<=n;j++) 17 { 18 scanf ("%d",&a[j]); 19 maxp=max(maxp,a[j]); 20 ant[a[j]]++; 21 } 22 int flag=0; 23 for(j=maxp;j>=1;j--)//从maxp~1枚举每个数 24 { 25 int num=0; 26 for(k=j;k<=maxp;k=k+j) 27 { 28 if(ant[k])//寻找k的倍数的个数。 29 num+=ant[k]; 30 if(num>1)//一旦找到了这样的数j,他的倍数个数大于1,则直接跳出循环。 31 { 32 flag=1; 33 printf("Case #%d: %d ",i,j); 34 break; 35 } 36 } 37 if(flag) 38 break; 39 } 40 } 41 return 0; 42 }
结论:当暴力不能解决问题的时候需要转个弯,从问题的深层次来思考,或者想出一种巧妙的办法,理解问题,拆开问题,才能不断打开思路。