知识点: 简单数论 , 质因数分解
原题面
题目要求:
定义: \(sgcd(x,y)\) 为 \(x,y\) 的 次大 公约数 ,
\(ps\) : 当 \(\gcd(x,y) = 1\) 时 , \(sgcd(x,y) = -1\)
给定 一数列 \(a\) ,
求: \(sgcd(a_1,a_1),sgcd(a_1,a_2),\dots,sgcd(a_1,a_n)\)
\(n\le 1e5, a_i\le 1e12\)
分析题意:
有: \(\large x = \prod\limits{p_i^{a_i}}\ ,\ y = \prod\limits{p_i^{b_i}}\ ,\ \gcd{(x,y)} =\prod\limits{p_i^{\min(a_i,b_i)}}\)
因为 \(\large sgcd|x , sgcd|y\) ,
显然 , \(\large sgcd = \frac{\gcd}{\min(p_i)}\ (\text{满足 } p_i|x , p_i|y)\)则, 若已知 \(\gcd(a_1,a_i)\) 与 \(\min(p_i) \ (\text{满足 } p_i|x , p_i|y)\) ,
即可求得 \(sgcd(a_1,a_i)\)\(\gcd(a_1,a_i)\) 可在 \(\log(n)\) 时间内 求得 ,
如何求得 \(\min(p_i) \ (\text{满足 } p_i|x , p_i|y)\) ?发现 \(a_1\) 对所有的 答案 都作出 贡献.
则有 : \(p_i|a_1 \Leftrightarrow p_i|\gcd(a_1,a_i)\)则 可以 预处理出\(a_1\) 的所有质因子 \(p_i\) ,
并 按照升序 , 将所有 \(p_i\) 对 \(\gcd(a_1,a_i)\) 进行试除
则, 能够 整除\(\gcd(a_1,a_i)\)的 第一个\(p_i\) , 即为所求的 \(\min(p_i)\)
算法实现:
- 对 \(a_i\) 进行 质因数分解
- 枚举 每一个 \(a_i\)
- 求得 \(\gcd(a_1,a_i)\)
- 枚举 \(a_1\) 的 质因子 , 并对 \(\gcd(a_1,a_i)\) 进行试除
- 找到 \(\min(p_i) \ (\text{满足 } p_i|x , p_i|y)\)
计算 \(\large sgcd = \frac{\gcd}{\min(p_i)}\)
以上算法 , 极限复杂度为 \(\Theta(\sqrt{a_1} +n(\log{n}+k))\) ,
一般 跑不满 , 稳过 .
//知识点:数论 ,质因数分解
/*
By:Luckyblock
1A开心
分析题意:
*/
#include
#include
#include
#define int long long
const int MARX = 1e5+10;
//=============================================================
int n,a1,ax;
std:: vector prime;//质因数分解 a1
//=============================================================
inline int read()
{
int s=1, w=0; char ch=getchar();
for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0';
return s*w;
}
int gcd(int a,int b) {return b?gcd(b,a%b):a;}//求 最大公约数
void split(int x)//质因数分解
{
for(int i=2; i*i <=x; i++)
{
if(x%i == 0) prime.push_back(i);
while(x%i == 0) x /= i;
}
if(x != 1) prime.push_back(x);
}
//=============================================================
signed main()
{
n = read(); a1 = read();
split(a1);
printf("%lld ",a1/prime[0]);//sgcd(a1,a1)
for(int i=2; i<=n; i++)
{
ax = read();
int d = gcd(a1,ax);
if(d == 1) {printf("-1 "); continue;}//无sgcd
for(int j=0,size=prime.size(); j