唯一分解定理 && 欧几里得算法——例题2: (大整数的)最大公约数

目录

欧几里得算法

最大公约数

题目描述

分析+代码


欧几里得算法

专门算两个数的最大公约数的算法,又称辗转相除法。即 gcd(a,b) = gcd(b,a%b)。很明显,边界是b = 0,返回a。

gcd(int a,int b) {
    return b == 0 ? a : gcd(b,a % b);
}

最大公约数

题目描述

已知N个数a1~an,这N个数的乘积为A,又已知M个数b1~bm,这M个数的乘积为B。求A,B的最大公约数。如果其最大公约数超过9位,则只需输出最后9位。

输入

第一行一个整数N.(1<=N<=1000)
第二行N个整数,均小于1000000000,它们的乘积为A

第三行一个整数M(1<=M<=1000)
第四行M个整数,均小于1000000000,它们的乘积为B

输出

一个整数,即A,B的最大公约数。若超过9位,则只输出9位。

样例输入

Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

3
2 3 5
2
4 5

样例输出

10

分析+代码

这道题数据很大,光用longlong还不行,每次乘法后都要取模,但是取模后就不能用gcd()了,这可怎么办呢?

还是要用唯一分解定理,但是已经没嫩么重要了。从题目中得知,A和B都是极大的整数(10^{9000}),不方便用高精,就不能直接求gcd(A,B)。

我们看,输入中已经把A和B都分成了各个整数的积,相当于在A,B的唯一分解中,已经分成了若干小块。

两个整数如果都除以它们的最大公约数,它们的唯一分解中就没有重复的,就是互质数,那时,A的因子的分解中也肯定没有与B的任意因子分解重合的部分,所以到那时,a1~an中的每一个数都与b1~bm中每一个数互质。这个把A,B转为互质数的过程,就可以代替为把A,B分解的因数(a1~an和b1~bm)一对(ai和bj)都转为互质。不难发现,一共有n*m次gcd()计算。在每一次计算gcd(ai,bj)时记录下gcd,最后求积就行。

最后是代码(要对自己负责!):

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define LL long long
#define max(x,y) (x > y ? x : y)
#define min(x,y) (x < y ? x : y)
using namespace std;
LL read() {
    LL f = 1,x = 0;char s = getchar();
    while(s < '0' || s > '9') {if(s == '-')f = -1;s = getchar();}
    while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
    return x * f;
}
LL a[1005],b[1005];
bool fl = 0;
LL n,m,i,j,k,s,o,num;
LL gcd(LL x,LL y) {
    return y == 0? x : gcd(y,x % y);
}
int main() {
    n = read();
    for(i = 1;i <= n;i ++) {
        a[i] = read();
    }
    m = read();
    for(i = 1;i <= m;i ++) {
        b[i] = read();
    }
    LL ans = 1;
    for(i = 1;i <= n;i ++) {
        for(j = 1;j <= m;j ++) {
            s = gcd(a[i],b[j]);
            a[i] /= s,b[j] /= s;
            ans *= s;
            if(ans > 1000000000) fl = 1,ans %= 1000000000;//当answer超过10^9时,要输出前导零
        }
    }
    if(fl && ans < 100000000) putchar('0');
    if(fl && ans < 10000000) putchar('0');
    if(fl && ans < 1000000) putchar('0');
    if(fl && ans < 100000) putchar('0');
    if(fl && ans < 10000) putchar('0');
    if(fl && ans < 1000) putchar('0');
    if(fl && ans < 100) putchar('0');
    if(fl && ans < 10) putchar('0');
    printf("%lld",ans);
    return 0;
}
 

下一篇:扩展欧几里得算法——例题3: 最大公约数问题1

posted @ 2019-03-25 13:36  DD_XYX  阅读(119)  评论(0编辑  收藏  举报