【uoj#48】[UR #3]核聚变反应强度 数论

题目描述

给出一个长度为 $n$ 的数列 $a$ ,求 $a_1$ 分别与 $a_1...a_n$ 的次大公约数。不存在则输出-1。

输入

第一行一个正整数 $n$ 。

第二行 $n$ 个用空格隔开的正整数,第 $i$ 个为 $a_i$ 。

$nle 10^5,a_ile 10^{12}$

输出

一行 $n$ 个用空格隔开的整数,第 $i$ 个表示 $ ext{sgcd}(a_1,a_i)$ 。

样例输入

4
12450 1 2 450

样例输出

6225 -1 1 75


题解

数论

次大公约数显然是最大公约数除以它的最小质因子得到的结果。

但是每次都求最大公约数,然后再找最小质因子的话,时间复杂度为 $O(nsqrt a)$ ,无法承受。

考虑:每次都是用 $a_1$ 与其它数求次大公约数,而最大公约数的因子一定是两个数的因子。

因此可以直接预处理出 $a_1$ 的所有质因子,然后每次枚举判断是否成立即可。

由于质因子只有 $O(log a)$ 个,因此时间复杂度为 $O(sqrt a+nlog a)$ 

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll a[100010] , v[40];
inline ll gcd(ll a , ll b)
{
	ll t;
	while(b) t = a , a = b , b = t % b;
	return a;
}
int main()
{
	int n , m = 0 , i , j;
	ll t;
	scanf("%d" , &n);
	for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &a[i]);
	for(i = 2 , t = a[1] ; 1ll * i * i <= t ; i ++ )
	{
		if(!(t % i))
		{
			v[++m] = i;
			while(!(t % i)) t /= i;
		}
	}
	if(t != 1) v[++m] = t;
	for(i = 1 ; i <= n ; i ++ )
	{
		t = gcd(a[1] , a[i]);
		for(j = 1 ; j <= m ; j ++ )
		{
			if(!(t % v[j]))
			{
				printf("%lld " , t / v[j]);
				break;
			}
		}
		if(j > m) printf("-1 ");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/GXZlegend/p/8185409.html