最大公约数 & 最小公倍数
最大公约数(gcd)
求解方法:
欧几里得算法(辗转相除法):
时间复杂度为\(O(logn)\)
递归形式:
int gcd(int a,int b){
return b>0?gcd(b,a%b):a;
}
非递归形式:
int gcd(int a,int b){
while(b){int c=a;a=b;b=c%b;}
return a;
}
更相减损术(辗转相减法):
适用于大整数求 \(\gcd\),比如高精度。
递归形式:
int gcd(int a,int b){
if(a==b) return a;
if(a<b) swap(a,b);
return gcd(a-b,b);
}
非递归形式:
int gcd(int a,int b){
while(a!=b){
if(a<b) swap(a,b);a-=b;
}
return a;
}
扩展欧几里得算法(exgcd):
用于求解 \(ax+by=\gcd(a,b)\) 的一组整数特解,并可用于求解逆元和线性同余方程。
首先按照辗转相除法向下递归,
即:
其中 \(a \bmod b = a-b \times \lfloor a/b \rfloor\),
那么,
设\(ax+by=\gcd(a,b)\),\((a-b \times \lfloor a/b \rfloor)x'+by'=\gcd(a,b)\)。
列出等式$$ax+by=(a-b \times \lfloor a/b \rfloor)x'+by'$$
解,得:\(\left\{\begin{aligned}x&=y'\\y&=x'-\lfloor a/b \rfloor\times y'\end{aligned}\right.\)
当递归进行到 \(b=0\) 时,可有一组解 \(\left\{\begin{aligned}x&=1\\y&=0\end{aligned}\right.\)
只需向上回溯时计算 \((x,y)\) 即可。
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int g=exgcd(b,a%b,x,y);
int t=x;x=y;y=t-a/b*y;
return g;
}
应用:
求 \(ax+by=\gcd(a,b)\) 的通解
利用欧几里得定理我们求出了 \(ax+by=\gcd(a,b)\) 的一组特解 \((x_0,y_0)\),令其解集为 \(U\)。
将 \(ax+by=\gcd(a,b)\) 变形得:
将 \(x_0,y_0\) 带入,得:
可以得到 \((\gcd(a,b)-ax_0) \mid b\)
可以推出 \((\gcd(a,b)-ax_0+lcm(a,b)) \mid b\)
可以得到:
此时对应的:
可以继续推出其他解:
求 \(ax'+by'=c,(c\mid\gcd(a,b))\) 的解
我们可以从 \(ax+by=\gcd(a,b)\),推出 \(ax'+by'=c\) 的一组整数特解,其中 \(c\mid\gcd(a,b)\)。
先用扩展欧几里得求出 \(ax+by=\gcd(a,b)\),的一组解\((x,y)\),再将整个方程乘 \(\frac{c}{\gcd(a,b)}\),得到 \(ax\frac{c}{\gcd(a,b)}+by\frac{c}{\gcd(a,b)}=c\)
即可得出 \(ax'+by'=c\) 的解为 \(\left\{\begin{aligned}x'=x\frac{c}{\gcd(a,b)}\\y'=y\frac{c}{\gcd(a,b)}\end{aligned}\right.\)
至于其他解,跟上面一样:
其中 \(n\in \Z\) 。
二分法快速求最大公因数(binary gcd):
该算法快于欧几里得算法。
int binary_gcd(int a,int b){
if(a==b) return a;
if(((a&1)|(b&1))==0) return gcd(a>>1,b>>1)<<1;
if((a&1)==0) return gcd(a>>1,b);
if((b&1)==0) return gcd(a,b>>1);
if(a<b) swap(a,b);
return gcd((a-b)>>1,b);
}
最小公倍数(lcm)
求解方法
int lcm(int a,int b){
return a*b/gcd(a,b);
}

浙公网安备 33010602011771号