一、GCD
1.定义
最大公因数(Greatest Common Divisor, GCD),指
两个或多个整数共有约数中最大的一个。
2.欧几里得算法(辗转相除法)
运算中有取模操作,不管是用递归写法,还是循环写法,对执行次数影响不大,所以整体可以控制在一个接近常数时间内完成。
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
3.辗转相除法简单证明
目标:证明GCD(a,b)==GCD(b,a%b)
1.证明 GCD(a,b) 是 b,a%b 的一个公约数
2.证明 GCD(a,b) 是 b,a%b 的最大的公约数
2.大数计算GCD优化
二、LCM
1.定义
两个或多个整数公有的倍数称为它们的公倍数,其
中除0 以外最小的一个公倍数是这些整数的 最小公
倍数。
2.LCM与GCD联系
三、LCM Walk
1.分析
终点为(ex,ey),我们设前一个点为(x,y)
令t=GCD(x,y)
x=pt;
y=qt;
则LCM(x,y)== x * y / t == p * q * t
而且作为最小公倍数,必定有LCM(x,y)>=max(x,y)
所以不管哪一方加上最小公倍数,ex,ey都会有大小区别,而且那个较大项就是进行了处理的位置。
若ex < ey,
说明
ex=x=p * t;
ey=y+LCM(x,y)= q * (1+p)* t;
根据辗转相除法可知 p 与(1+p)为互质关系,而 p 、q 就是互质关系,
所以:
GCD(ex,ey)== GCD(x,y)== t
此时,x就等于ex,
y == ey - LCM(x,y) == ey - p * t * q == ey - ex * q == ey - ex * ey /(t+ex)
==(ey * t)/(ex + t)
由此我们就可以直接从(ex,ey)得到(x,y)。
但我们需要y为一个整数,才能找到一个准确的点,所以此时若y%(x+t)!=0时,将无法逆推,即不存在满足要求的点。
//终点也可以视作一步未走的起点。
2.代码
#include<iostream>
#include<algorithm>
using namespace std;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int x,y,T;
cin>>T;
for(int i=1;i<=T;i++){
cin>>x>>y;
if(x<y) swap(x,y);
int k=gcd(x,y),cnt=1;
while(x%(y+k)==0){
cnt++;
x=x/(y/k+1);
if(x<y) swap(x,y);
}
printf("Case #%d: %d\n",i,cnt);
}
return 0;
}