Codeforces Round #641 (Div. 2) C. Orac and LCM

本文探讨了一个数学算法问题,即给定一系列整数,如何计算这些整数中任意两个数的最小公倍数(LCM)的集合的最 大公约数(GCD)。文章详细阐述了解决这一问题的思路,包括质因数分解的重要性,以及如何通过统计每个质因子在数列中的出现次数来确定最终的答案。通过具体的代码实现,展示了算法的高效性和准确性。

题意:给了n个数,让求gcd{ lcm{a[i],a[j]} } (i<j)
就是n个数,两两配对求出他们的lcm,对于所有lcm在求出gcd

 


思路:考虑一下gcd和lcm在算术基本定理下的含义。

x=p_{1}^{a1}*p_{2}^{a2}*p_{3}^{a3}*.....*p_{k}^{ak}

y=p_{1}^{b1}*p_{2}^{b2}*p_{3}^{b3}*...*p_{k}^{bk}

那么容易知道

lcm(x,y)=y=p_{1}^{max(a1,b1)}*p_{2}^{max(a2,b2)}*p_{3}^{max(a3,b3))}*...*p_{k}^{max(ak,bk)}

gcd(x,y)=y=p_{1}^{min(a1,b1)}*p_{2}^{min(a2,b2)}*p_{3}^{min(a3,b3))}*...*p_{k}^{min(ak,bk)}

那么对于两两组合求lcm,我们容易知道取的质因数是最大的那个,然后整体求gcd质因数取的是最小的。

那么考虑一下。如果对于n个数而言,有n-1个数都含有质因数x,那么最后的所求答案的gcd一定有质因数x,为什么?

因为只存在一个数字没有质因子x,那么因为lcm是取最大的,所以别的数都有,配对时候可以把他拉上来,也就是求出来的lcm是有的。

那么容易知道对于质因数x,n个数内,如果含有质因子x的个数<n-1个,那么lcm必有两个是无法含有x因子的,那么gcd取得是最小,所以对答案没有贡献。

那么还有一种呢? 就是n个数都含有质因子x,考虑一下前面所说得,lcm取得是最大,对于最小的那个,一定会被拉到和含有x因子个数第二小一样,整体gcd取最小,那么自然是含有x因子个数第二个小的那个。

那么做法就很清楚了。

把每个数的每个质因子个数都求出来。

如果有n-1个数含有质因子x,那么答案就乘上x^k[x][0],k[x]数组为还有x因子的个数,k[x][0]是含有个数最少的。

如果有n个数含有质因子x,那么答案就乘上x^k[x][1],k[x]数组为还有x因子的个数,k[x][1]是含有个数第二少的。

其实本质都是乘x^k[x][1],这里你可以会问,那为什么如果有n-1个数含有质因子x,我的幂是k[x][0]而不是k[x][1]

这个看个人写法,我的写法是不含有x因子的,也就是含有个数是0个,就没丢到数组内,其实丢进去那一个不含有的,也就是含有个数为0,那么就统一了幂是第二小。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll a[2000005],c[2000005];
vector<int> k[2000005];
ll qpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=a*ans;
        b>>=1;
        a=a*a;
    }
    return ans;
}
int main(){

    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        int x=a[i];
        for(int j=2;j*j<=x;j++){
            if(x%j==0){
                c[j]++;
                int num=0;
                while(x%j==0) x/=j,num++;
                k[j].push_back(num);
            }
        }
        if(x!=1){
            c[x]++;
            k[x].push_back(1);
        }
    }
    ///k[i][j]数组表示质因子为i的第j个的个数
    for(int i=1;i<=200000;i++) sort(k[i].begin(),k[i].end());
    ll qq=1;
    for(int i=1;i<=200000;i++){
        if(c[i]>=n-1){
            if(c[i]==n-1) qq*=qpow(i,k[i][0]);
            else qq*=qpow(i,k[i][1]);
        }
    }
    cout<<qq;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不会c语言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值