给出N个正整数,找出N个数两两之间最大公约数的最大值。例如:N = 4,4个数为:9 15 25 16,两两之间最大公约数的最大值是15同25的最大公约数5。
Input
第1行:一个数N,表示输入正整数的数量。(2 <= N <= 50000) 第2 - N + 1行:每行1个数,对应输入的正整数.(1 <= S[i] <= 1000000)
Output
输出两两之间最大公约数的最大值。
Input示例
4 9 15 25 16
Output示例
5
思路:尝试了两种方法,两种方法都是记录某个数作为因子出现的次数, 当这个因子出现两次时它必定是某两个数的公共因数。
第一种是对每个数作因数分解后累计因子出现的次数,第二种是筛法。
实测第二种方法更快,我猜测是因为N和max(s[i])的值并不大,加上第二种方法是从大到小找,只要找到第一个公因数即为答案,所以快了很多
AC代码1(分解因数):
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; const int N=5e4+5; const int INF=1e6+5; int s[N],cnt[INF]; int main() { int n; int maxx=0; scanf("%d", &n); for(int i=0;i<n;i++){ scanf("%d", &s[i]); if(maxx<s[i]) maxx=s[i]; } memset(cnt, 0, sizeof(cnt)); int res=1; for(int i=0;i<n;i++) { for(int j=1;j*j<=s[i];j++){ if(s[i]%j==0){ cnt[j]++; if(j*j!=s[i]) cnt[s[i]/j]++; } } } for(int i=2;i<=maxx;i++) if(cnt[i]>1){ res=i; } printf("%d\n", res); return 0; }
AC代码2(筛法):
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; const int N=5e4+5; const int INF=1e6+5; int s[N],cnt[INF]; int main() { int n; int maxx=0; scanf("%d", &n); memset(cnt, 0, sizeof(cnt)); for(int i=0;i<n;i++){ scanf("%d", &s[i]); cnt[s[i]]++; if(maxx<s[i]) maxx=s[i]; } int res=1; for(int i=maxx;i>0;i--) { int t=0; for(int j=i;j<=maxx;j+=i){ t+=cnt[j]; if(t>1){ res=i; i=-1; break; } } } printf("%d\n", res); return 0; }