UOJ48 【UR #3】核聚变反应强度 题解
题目链接:#48. 【UR #3】核聚变反应强度
题意:
著名核物理专家 Picks 提出了核聚变特征值这一重要概念。
核聚变特征值分别为 $x$ 和 $y$ 的两个原子进行核聚变,能产生数值为 $\text{sgcd}(x, y)$ 的核聚变反应强度。
其中, $\text{sgcd}(x, y)$ 表示 $x$ 和 $y$ 的次大公约数,即能同时整除 $x, y$ 的正整数中第二大的数。如果次大公约数不存在则说明无法核聚变, 此时 $\text{sgcd}(x, y) = -1$。
现在有 $n$ 个原子,核聚变特征值分别为 $a_1, a_2, \dots, a_n$。然后 Picks 又从兜里掏出一个核聚变特征值为 $a_1$ 的原子,你需要计算出这个原子与其它 $n$ 个原子分别进行核聚变反应时的核聚变反应强度,即
输入格式:
第一行一个正整数 $n$。
第二行 $n$ 个用空格隔开的正整数,第 $i$ 个为 $a_i$。
输出格式:
一行 $n$ 个用空格隔开的整数,第 $i$ 个表示 $\text{sgcd}(a_1, a_i)$。
C/C++ 输入输出 long long 时请用
%lld
。由于本题数据量较大,建议不要使用 cin/cout 进行输入输出。数据范围:
$n \le 10^5,a_i \le 10^{12}$
啥?我就用cin/cout你打我啊??
首先很容易想到,这个 $\text{sgcd}(a,b)$ 其实就是 $\gcd(a,b)$ 去除以它的最小素因子。
这就是暴力解法。把 $10^6$ 以内的所有素数都筛出来,然后暴力找 $\gcd(a_1,a_i)$ 的最小素因子
时间复杂度 $O\left(\frac{M}{\ln M} + n\frac{\sqrt{a_i}}{\ln a_i}\right),M=10^6$ ,显然过不了这题。
注:这里的复杂度其实是利用了「 不超过 $x$ 的素数有 $O\left(\frac{x}{\ln x}\right)$ 个」这个性质分析的。
考虑优化这个暴力
注意到这个最小素因子一定是 $a_1$ 的质因子
然后我们预处理 $a_1$ 的质因子就好了
时间复杂度 $O(\sqrt{a_1} + n \log a_1)$
代码:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N ((int)())
int n,cnt;
int A,B,p[55];
int gcd(int a,int b) {return b==0 ? a : gcd(b,a%b);}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n >> A; B=A;
for(int i=2; i*i <= B; i++)
if(B%i==0) for(p[++cnt] = i; B%i==0; B/=i);
if(B>1) p[++cnt] = B; p[++cnt]=-1;
cout << (A / p[1]) << ' ';
while(--n)
{
cin >> B; B = gcd(A,B);
for(int i=1; i<=cnt; i++)
if(B%p[i] == 0) {cout << (B / p[i]) << " \n"[n==1]; break;}
}
return 0;
}
参考文献:
[1] https://yhx-12243.github.io/OI-transit/records/uoj48.html