又一道 GCD 问题
题目链接:nowcoder 213804
到主站看:https://blog.csdn.net/weixin_43346722/article/details/112740731
题目大意
给你一个数组,要你求出从他们中选出 个的 gcd 的最大值。
思路
看到这道题,我们考虑看有多少个数有 这个因子,设其为
。
那我们分解一下质因子(用素数筛选法和 floor(sqrt()) 来加速),然后 dfs 一下,就可以得到一个数的每个因子,就从而求出了 。
那有了这个,我们可以求出要选出 个数的 gcd 最大值是多少了。
(就是从后往前搜第一个 大于等于
的数)
那我们可以先弄出刚刚好是 个数的,然后再从后往前跑最大值。
然后就可以得出答案了。
具体实现可以看看代码。
代码
#include<cmath> #include<cstdio> #include<iostream> using namespace std; int n, a[100001], su[50001], all[100001], tmpn, tmp, ans[100001], maxn, zyz[1001], numm[1001]; bool susu[100100]; void getsusu() {//素数筛选法筛出素数 susu[1] = susu[0] = 1; for (int i = 2; i <= maxn + 100; i++) if (!susu[i]) { su[++su[0]] = i; for (int j = i + i; j <= maxn + 100; j += i) susu[j] = 1; } } void dfs(int now, int sum) { if (now == zyz[0] + 1) { all[sum]++; return ; } int tmpp = 1; for (int i = 0; i <= numm[now]; i++) {//对于这一个因数,选多少个乘 dfs(now + 1, sum * tmpp); tmpp *= zyz[now]; } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); maxn = max(maxn, a[i]); ans[i] = 1; } getsusu(); for (int i = 1; i <= n; i++){ zyz[0] = 0;//分解质因数 tmpn = a[i]; tmp = floor(sqrt(a[i])); for (int j = 1; su[j] <= tmpn && j <= tmp; j++) { if (tmpn % su[j] == 0) { zyz[++zyz[0]] = su[j]; numm[zyz[0]] = 0; while (tmpn % su[j] == 0) { numm[zyz[0]]++; tmpn /= su[j]; } } } if (tmpn != 1) { zyz[++zyz[0]] = tmpn; numm[zyz[0]] = 1; } dfs(1, 1);//标记每一个因数 } for (int i = maxn; i >= 1; i--) { if (ans[all[i]] == 1) ans[all[i]] = i; } for (int i = n - 1; i >= 2; i--)//选 i 个也可以在 i+x 个中选 i 个,不一定要刚刚好 ans[i] = max(ans[i + 1], ans[i]); for (int i = 2; i <= n; i++) printf("%d ", ans[i]); return 0; }