链接:https://ac.nowcoder.com/acm/contest/9984/J
来源:牛客网
众所周知,邬澄瑶正在学习欧几里得算法。
现在她已经可以轻松求解 gcd(x1,⋯,xn),并为此洋洋得意。为了整治狂妄自大的邬澄瑶,她的室友把$gcd(x_{1}{p_1},⋯,x_{n}{p_n}) $这个式子甩给了他。
邬澄瑶被难住了,只好来求助于你,希望你帮她求出这个式子。
由于结果可能很大,你需要对 1e9+7 取模。
特别的,邬澄瑶的室友认为 gcd(x)=x 。
输入描述:
第一行一个数表示 n 。
第二行 n 个数,第 i 个数表示 xixi 。
第三行 n 个数,第 i 个数表示 pipi 。
其中,1≤n,xi,pi≤1e41≤n,xi,pi≤1e4 。
输出描述:
输出一行一个数表示答案。
示例1
输入
复制
2
9 3
1 2
输出
复制
9
直接暴力显然不可取,考虑gcd的性质:
设(a=p_1^{a1}p_2^{a2}p_3^{a3}... b = p_1^{b1}p_2^{b2}p_3^{b3}),联想唯一分解定理,则(gcd(a, b) = p_1^{min(a1,b1)}p_2^{min(a2,b2)}p_3^{min(a3,b3)}...)
拓展到多个数的gcd同样成立。对于本题,要求的是多个幂次的gcd,其实只需要在取min的时候给质数的指数乘上次幂。比如设(a=p_1^{a1}p_2^{a2}p_3^{a3}... b = p_1^{b1}p_2^{b2}p_3^{b3}),联想唯一分解定理,则(gcd(a^s, b^t) = p_1^{min(a1 imes s,b1 imes t)}p_2^{min(a2 imes s,b2 imes t)}p_3^{min(a3 imes s,b3 imes t)}...)
观察到数的范围是1e4,因此开一个数组factor,factor[i]代表i这个质数(如果是质数的话,不是质数幂次为0自然没有影响)的幂次(在gcd中)。对于题目的每个x先进行唯一分解,根据分解得到的质数pi来更新factor数组,即factor[pp[i]] = min(factor[pp[i]], cc[i] * np);cc[i]就是x分解后得到的当前这个质数的次数,np是x原本的次数。当然如果当前factor[i]是0的话就直接赋值,不是0再取min。最后用快速幂计算gcd即可:(GCD = Sigma_{i = 1}^{10000}i^{factor[i]})。
但直接这么写会有问题:比如某个x其分解后的质因子不包含5,而factor[5]已经在遍历到别的x的时候被更新为非0数了,这时候根据上面公式应该把factor[5]设置为0,但如果对于每个x都要把范围内所有质数判断一遍的话显然会爆炸。因此可以再开一个cnt数组,cnt[i]代表所有x里质因子包含i这个质数(如果是质数的话)的x的个数。factor[i]不为0当且仅当cnt[i] == n(即输入的x的总个数),最后遍历计算的时候判断一下即可。复杂度是(nsqrt{n})。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define mod 1000000007
using namespace std;
long long x[10005], p[10005];
int n;
long long fpow(long long aa, long long bb)
{
long long ans = 1;
for(; bb; bb >>= 1)
{
if(bb & 1) ans = ans * aa % mod;
aa = aa * aa % mod;
}
return ans;
}
long long pp[10005], cc[10005];//唯一分解定理板子,pp存分解出来的质数,cc存对应的次幂
int m = 0;
long long factor[10005], cnt[10005];
void divide(long long nn, long long np)
{
m = 0;
for(long long i = 2; i <= sqrt(nn); i++)
{
if(nn % i == 0)
{
pp[++m] = i, cc[m] = 0;
while(nn % i == 0) nn /= i, cc[m]++;
}
}
if(nn > 1) pp[++m] = nn, cc[m] = 1;
for(int i = 1; i <= m; i++)//分解完后更新factor数组
{
if(factor[pp[i]]) factor[pp[i]] = min(factor[pp[i]], cc[i] * np);
else factor[pp[i]] = cc[i] * np;
cnt[pp[i]]++;
}
}
int main()
{
freopen("data.txt", "r", stdin);
memset(factor, 0, sizeof(factor));
cin >> n;
for(int i = 1; i <= n; i++) cin >> x[i];
for(int i = 1; i <= n; i++) cin >> p[i];
for(int i = 1; i <= n; i++) divide(x[i], p[i]);
long long ans = 1;
for(int i = 2; i <= 10000; i++)
if(cnt[i] == n)
ans = ans * fpow(i, factor[i]) % mod;
cout << ans;
return 0;
}