题意
求从n个数中取i个数的最大的最大公约数 (i从1到k)
输入
二行
第一行两个整数n和k
第二行k个数ai (i∈[1,k])
输出
n行 分别表示取i个数的最大公约数
【数据范围】
记输入数据中能力值的最大值为inf。
对于20%的数据,n<=5,inf<=1000
对于另30%的数据,n<=100,inf<=10
对于100%的数据,n<=10000,inf<=1e6
题解
一开始简单的想到了一个递推式: 取i个数的最大公约数是取i-1个数的最大公约数和其他未用过的数的最大的最大公约数
即f[i] = max (f[i], gcd (f[i-1], a[j])) (i∈[1, n], j∈[1,k])
但可想而知,这个算法的时间复杂度太大了
那么我们考虑到对ai分别求出其因数并计数,即记录a1到an的数的因数分别出现了几次,得到计数数组c[N] N = max (a1 ~ an);
在考虑之前的递推式,很显然取1个数的时候答案为最大的因数,取i个数时的答案很显然要小于等于取i-1个数的答案
所以我们从a1到an中的最大值开始向下搜索:
如果该数num的c[num] >= i 便满足要求输出即可
AC代码
#include <bits/stdc++.h>
using namespace std;
static const int N = 1e6 + 10;
int n, _max = 0, c[N];
int main ()
{
scanf ("%d", &n);
for (int i = 1; i <= n; ++i)
{
int num;
scanf ("%d", &num);
_max = max (_max, num);
int m = sqrt (num);
for (int i = 1; i <= m; ++i)
if (num % i == 0)
{
++c[i];
if (num != i * i)
++c[num/i];
}
}
int num = _max;
for (int i = 1; i <= n; ++i)
{
for (; c[num] < i ;)
--num;
printf ("%d\n", num);
}
return 0;
}