线性筛+暴力分解质因数+快速幂
首先对于(gcd(x_1, x_2, ..., x_n))有两种解法
- 辗转相除法,每次用辗转相除法求两个数的gcd,然后用结果再和下一个数求gcd即可
- 对每个(x_i) 分解质因子,n个数的最大公倍数就是:n个数所有(公共质因子的最小次幂 )的积
对于方法2,举个例子:
(12 = 2^2*3)
(8 = 2^3)
(18=2*3^2)
(10=2*5)
那么这三个数的最大公因数就是:(2^{min(2,3,1,1)}*3^{min(1,0,2,0)}*5^{min(0,0,0,1)} = 2^1 = 2)
由于((x^a)^b = x^{a*b})
所以假设 (x_i)可以质数分解成为:(x_i = p_{i1}^{k_{i1}}* p_{i2}^{k_{i2}}*...* p_{it}^{k_{it}});其中(p_{ij})表示分解的质数, (k_{ij})表示该质数的幂
(x_i^{b_i} = p_{i1}^{k_{i1} * b_i}* p_{i2}^{k_{i2}*b_i}*...* p_{it}^{k_{it}*b_i})
其中质数分解,直接暴力分解即可。
我们的任务就是找出每个质数最小的幂(没有这个质数,幂就是0),然后用快速幂相乘即可。
需要注意的是,对任意一个数分解质因子时,要求出1-10000所有质数的幂,比如 (10= 2^1*3^0*5^1*7^0*11^0*...) ,因为这里的0次也是有用的,表示n个数该质因子最小幂次是0,不能省略掉。
ac代码
// 分解质因数,求每个数所有质因数及其幂次
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mod = 1e9+7;
int cnt=0;
int vis[10010]; //
int x[10010], p[10010], prime[10010]; // prime存质数
int num[10010]; // 存每个质数的最小幂次,初始化成0x7f7f7f7f; num[i]表示prime[i]的最小幂次
int n;
// 快速幂
ll ksm(int n, int k)
{
ll ans = 1;
ll tot = n;
while(k){
if(k&1) ans=ans*tot%mod;
tot = tot*tot%mod;
k>>=1;
}
return ans%mod;
}
// 打印质数表
void table(int n)
{
memset(vis, 0, sizeof(vis));
for(int i=2; i<=n; ++i){
if(!vis[i])
prime[cnt++]=i;
for(int j=0; j<cnt && 1ll*i*prime[j]<=n; ++j){
vis[i*prime[j]] = 1;
if(i%prime[j]==0) break;
}
}
}
int main()
{
table(10000);
scanf("%d",&n);
for(int i=0; i<n; ++i){
scanf("%d", &x[i]);
}
for(int i=0; i<n; ++i){
scanf("%d", &p[i]);
}
memset(num, 0x7f7f7f7f, sizeof(num));
for(int i=0; i<n; ++i){
for(int j=0; j<cnt; ++j){ // 暴力分解质因数即可; 要分解出所有的质因数,包括幂次 为0的
// if(x[i] == 1) break;
// if(x[i]%prime[j]!=0) continue;
int t=0;
while(x[i]%prime[j]==0) {
x[i]/=prime[j];
t++;
}
num[j] = min(num[j], t*p[i]);
}
}
ll ans=1;
for(int i=0; i<cnt; ++i){
if(num[i]==0) continue;
ans = ans*ksm(prime[i], num[i])%mod;
}
printf("%lld", ans);
}
时间复杂度:(O(n))