根据教师课件,写成本文。未经允许,禁止转载。
gcd \gcd gcd,即最大公约数,指的是几个整数中公有的约数中最大的一个。
问题
已知 a , b a,b a,b,求 gcd ( a , b ) \gcd(a,b) gcd(a,b)。
方法一:枚举法
从 min ( a , b ) \min(a,b) min(a,b) 到 1 1 1 枚举,找到第一个 x x x 符合题意,就退出循环。
时间复杂度 O ( min ( a , b ) ) \mathcal O(\min(a,b)) O(min(a,b))。
方法二:分解质因数
令 a = p 1 x 1 p 2 x 2 … p n x n a=p_1^{x_1}p_2^{x_2}\dots p_n^{x_n} a=p1x1p2x2…pnxn, b = p 1 y 1 p 2 y 2 … p n y n b=p_1^{y_1}p_2^{y_2}\dots p_n^{y_n} b=p1y1p2y2…pnyn,其中 x i , y i ≥ 0 x_i,y_i\ge0 xi,yi≥0 且不同时为 0。
则 gcd ( a , b ) = p 1 min ( x 1 , y 1 ) p 2 min ( x 2 , y 2 ) … p 3 min ( x 3 , y 3 ) \gcd(a,b)=p_1^{\min(x_1,y_1)}p_2^{\min(x_2,y_2)}\dots p_3^{\min(x_3,y_3)} gcd(a,b)=p1min(x1,y1)p2min(x2,y2)…p3min(x3,y3)。
时间复杂度 O ( min ( a , b ) ) \mathcal O(\sqrt{\min(a,b)}) O(min(a,b))。
void Gcd()
{
for(int x=2;x*x<=min(a,b);x++)
{
while (a % x==0 && b % x==0) {a/=x;b/=x;ans*=x;}
while (a % x==0)a/=x;
while (b % x==0)b/=x;
}
if (a % b==0)ans*=b;
else if (b % a==0)ans*=a;
printf("%d",ans);
}
方法三:辗转相除(欧几里得算法)
定理: gcd ( a , b ) = gcd ( b , a % b ) \gcd(a,b)=\gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)。
证明:
设 gcd ( a , b ) = p \gcd(a,b)=p gcd(a,b)=p,则有 a = a ′ ∗ p , b = b ′ ∗ p , gcd ( a ′ , b ′ ) = 1 a=a'*p,b=b'*p,\gcd(a',b')=1 a=a′∗p,b=b′∗p,gcd(a′,b′)=1。
a % b = a − ⌊ a b ⌋ ∗ b = a ′ ∗ p − ⌊ a b ⌋ ∗ b ′ ∗ p = p ∗ ( a ′ − ⌊ a b ⌋ ∗ b ′ ) a\%b=a-\lfloor\frac{a}{b}\rfloor *b=a'*p-\lfloor\frac{a}{b}\rfloor*b'*p=p*(a'-\lfloor\frac{a}{b}\rfloor*b') a%b=a−⌊ba⌋∗b=a′∗p−⌊ba⌋∗b′∗p=p∗(a′−⌊ba⌋∗b′)。
gcd ( b , a % b ) = gcd ( b ′ ∗ p , p ∗ ( a ′ − ⌊ a b ⌋ ∗ b ′ ) ) = p ∗ gcd ( b ′ , a ′ − ⌊ a b ⌋ ∗ b ′ ) \gcd(b,a\%b)=\gcd(b'*p,p*(a'-\lfloor\frac{a}{b}\rfloor*b'))=p*\gcd(b',a'-\lfloor\frac{a}{b}\rfloor*b') gcd(b,a%b)=gcd(b′∗p,p∗(a′−⌊ba⌋∗b′))=p∗gcd(b′,a′−⌊ba⌋∗b′)。
现证明 gcd ( b ′ , a ′ − ⌊ a b ⌋ ∗ b ′ ) = 1 \gcd(b',a'-\lfloor\frac{a}{b}\rfloor*b')=1 gcd(b′,a′−⌊ba⌋∗b′)=1,使用反证法。假设 g c d ( b ′ , a ′ − ⌊ a b ⌋ ∗ b ′ ) = t ( t > 1 ) gcd(b',a'-\lfloor\frac{a}{b}\rfloor*b')=t(t>1) gcd(b′,a′−⌊ba⌋∗b′)=t(t>1)。
b ′ = b ′ ′ ∗ t b'=b''*t b′=b′′∗t, a ′ − ⌊ a b ⌋ ∗ b ′ = c ′ ∗ t a'-\lfloor\frac{a}{b}\rfloor*b'=c'*t a′−⌊ba⌋∗b′=c′∗t。
a ′ = c ′ ∗ t + ⌊ a b ⌋ ∗ b ′ = c ′ ∗ t + ⌊ a b ⌋ ∗ b ′ ′ ∗ t = t ∗ ( c ′ + ⌊ a b ⌋ ∗ b ′ ′ ) a'=c'*t+\lfloor\frac{a}{b}\rfloor*b'=c'*t+\lfloor\frac{a}{b}\rfloor*b''*t=t*(c'+\lfloor\frac{a}{b}\rfloor*b'') a′=c′∗t+⌊ba⌋∗b′=c′∗t+⌊ba⌋∗b′′∗t=t∗(c′+⌊ba⌋∗b′′)。
则 gcd ( a ′ , b ′ ) ≥ p \gcd(a',b')\ge p gcd(a′,b′)≥p,与 gcd ( a ′ , b ′ ) = 1 \gcd(a',b')=1 gcd(a′,b′)=1 矛盾,因此 gcd ( b ′ , a ′ − ⌊ a b ⌋ ∗ b ′ ) = 1 \gcd(b',a'-\lfloor\frac{a}{b}\rfloor*b')=1 gcd(b′,a′−⌊ba⌋∗b′)=1。
gcd ( b , a % b ) = p = gcd ( a , b ) \gcd(b,a\%b)=p=\gcd(a,b) gcd(b,a%b)=p=gcd(a,b)。
时间复杂度 O ( log ( max ( a , b ) ) ) \mathcal O(\log(\max(a,b))) O(log(max(a,b)))。
分析:
-
设 a > b a>b a>b。
若 a > 2 b a>2b a>2b,则 b ≤ a 2 b\le \frac{a}{2} b≤2a,规模减小一半。反之 a < 2 b a<2b a<2b,则 a % b < a 2 a\%b<\frac{a}{2} a%b<2a。
因此时间复杂度是 log \log log 级别。
-
斐波那契分析:传送门。
int Gcd(int a,int b)
{
if (b==0) return a;
else return Gcd(b,a % b);
}
方法四:二进制法
当 a < b a<b a<b 时, gcd ( a , b ) = gcd ( b , a ) \gcd(a,b)=\gcd(b,a) gcd(a,b)=gcd(b,a)。
当 a = b a=b a=b 时 gcd ( a , b ) = a \gcd(a,b)=a gcd(a,b)=a。
当 a , b a,b a,b 同为偶数时, gcd ( a , b ) = 2 ∗ gcd ( a 2 , b 2 ) \gcd(a,b)=2*\gcd(\frac{a}{2},\frac{b}{2}) gcd(a,b)=2∗gcd(2a,2b)。
当 a a a 为偶数, b b b 为奇数时, gcd ( a , b ) = gcd ( a 2 , b ) \gcd(a,b)=\gcd(\frac{a}{2},b) gcd(a,b)=gcd(2a,b)。
当 a a a 为奇数, b b b 为偶数时, gcd ( a , b ) = gcd ( a , b 2 ) \gcd(a,b)=\gcd(a,\frac{b}{2}) gcd(a,b)=gcd(a,2b)。
当 a , b a,b a,b 为奇数时, gcd ( a , b ) = gcd ( a − b , b ) \gcd(a,b)=\gcd(a-b,b) gcd(a,b)=gcd(a−b,b)。
注:此法适合高精度求最大公约数。
int Gcd(int m,int n)
{
if (m==n) return m;
if (m<n) return Gcd(n,m);
if (m & 1==0) return (n & 1==0)? 2*Gcd(m/2,n/2):Gcd(m/2,n);
return (n & 1==0)? Gcd(m,n/2): Gcd(n,m-n);
}