#48. 【UR #3】核聚变反应强度

知识点: 简单数论 , 质因数分解

原题面

题目要求:

定义: \(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)\)


算法实现:

  1. \(a_i\) 进行 质因数分解
  2. 枚举 每一个 \(a_i\)
    1. 求得 \(\gcd(a_1,a_i)\)
    2. 枚举 \(a_1\) 的 质因子 , 并对 \(\gcd(a_1,a_i)\) 进行试除
    3. 找到 \(\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<cstdio>
#include<ctype.h>
#include<vector>
#define int long long
const int MARX = 1e5+10;
//=============================================================
int n,a1,ax;
std:: vector <int> 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<size; j++)//枚举每一个 a1的 质因子 
	  	if(d % prime[j] == 0)//进行试除 
		{
		  printf("%lld ",d/prime[j]); //输出sgcd 
		  break;
		} 
	}
}
posted @ 2019-10-07 21:45  Luckyblock  阅读(154)  评论(1编辑  收藏  举报