链接:https://ac.nowcoder.com/acm/contest/40229/D
来源:牛客网题目描述
给一个长度为 n 的序列a:a1,a2 ⋯an 。
定义序列的最大 gcd 为:每次选择两个正整数 i,j(1≤i<j≤n),最大的gcd(ai,aj) 即为这个序列的最大 gcd。
输入描述:
第一行一个整数 n(2≤n≤1×10e6)。
第二行 n 个正整数 a1,a2,a3,⋯,an(1≤ai≤10e6),表示序列 a。输出描述:
一个整数,表示这个序列的最大 gcd。
当一个数g是一个数num的因数时,可以得出k*g = num,因此只要开个标记用的数组,记录给定的数组中的每一个数及出现次数,并枚举k和g,如果k*g的值存在于标记数组中,并总的出现次数大于等于2,则g是给定数组的公因数。 求出最大的g即可。
时间复杂度:首先要枚举g,从1到1e6(最坏情况),然后枚举k, 因为k*g<1e6, 所以时间复杂度为 n*(1e6/1+1e6/2+...+1e6/1e6),由于括号里的式子是调和级数,值约等于
1e6ln(n), 所以时间复杂度为O(nlogn)。
代码如下:
#include<iostream>
const int N = 1e6 + 5;
using namespace std;
int nums[N];
int fg[N] {0};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int n;
cin >> n;
int maxv = 0;
for(int i=0; i<n; i++) cin >> nums[i], fg[nums[i]] ++; //用数组记录每一个数
for(int g=1; g<N; g++)
{
int sum = 0;
for(int k=1; k*g<N; k++)
sum += fg[k*g];
if(sum>=2) maxv = max(maxv, g); //当sum>=2时,说明至少有两个数的最大公约数是g
}
cout << maxv << endl;
return 0;
}