【nowcoder 213804】又一道 GCD 问题

又一道 GCD 问题

题目链接:nowcoder 213804

到牛客看:

——>点我跳转<——

题目大意

给你一个数组,要你求出从他们中选出 2 ∼ n 2\sim n 2n 个的 gcd 的最大值。

思路

看到这道题,我们考虑看有多少个数有 x x x 这个因子,设其为 f x f_x fx

那我们分解一下质因子(用素数筛选法和 floor(sqrt()) 来加速),然后 dfs 一下,就可以得到一个数的每个因子,就从而求出了 f x f_x fx

那有了这个,我们可以求出要选出 y y y 个数的 gcd 最大值是多少了。
(就是从后往前搜第一个 f i f_i fi 大于等于 y y y 的数)

那我们可以先弄出刚刚好是 y y y 个数的,然后再从后往前跑最大值。

然后就可以得出答案了。

具体实现可以看看代码。

代码

#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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/112740731
gcd