目录
欧几里得算法
最大公约数
题目描述
分析+代码
专门算两个数的最大公约数的算法,又称辗转相除法。即 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都是极大的整数(),不方便用高精,就不能直接求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
#include
#include
#include
#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