Loading

浅谈最大公约数

根据教师课件,写成本文。未经允许,禁止转载。

\(\gcd\),即最大公约数,指的是几个整数中公有的约数中最大的一个。

问题

已知 \(a,b\),求 \(\gcd(a,b)\)

方法一:枚举法

\(\min(a,b)\)\(1\) 枚举,找到第一个 \(x\) 符合题意,就退出循环。

时间复杂度 \(\mathcal O(\min(a,b))\)

方法二:分解质因数

\(a=p_1^{x_1}p_2^{x_2}\dots p_n^{x_n}\)\(b=p_1^{y_1}p_2^{y_2}\dots p_n^{y_n}\),其中\(x_i,y_i\ge0\) 且不同时为 0。

\(\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)}\)

时间复杂度 \(\mathcal O(\sqrt{\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)=p\),则有 \(a=a'*p,b=b'*p,\gcd(a',b')=1\)

\(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')\)

\(\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'-\lfloor\frac{a}{b}\rfloor*b')=1\),使用反证法。假设 \(gcd(b',a'-\lfloor\frac{a}{b}\rfloor*b')=t(t>1)\)

\(b'=b''*t\)\(a'-\lfloor\frac{a}{b}\rfloor*b'=c'*t\)

\(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'')\)

\(\gcd(a',b')\ge p\),与 \(\gcd(a',b')=1\) 矛盾,因此 \(\gcd(b',a'-\lfloor\frac{a}{b}\rfloor*b')=1\)

\(\gcd(b,a\%b)=p=\gcd(a,b)\)


时间复杂度 \(\mathcal O(\log(\max(a,b)))\)

分析:

  1. \(a>b\)

    \(a>2b\),则 \(b\le \frac{a}{2}\),规模减小一半。反之 \(a<2b\),则 \(a\%b<\frac{a}{2}\)

    因此时间复杂度是 \(\log\) 级别。

  2. 斐波那契分析:传送门


int Gcd(int a,int b)
{
    if (b==0) return a;
    else return Gcd(b,a % b);
}

方法四:二进制法

\(a<b\) 时, \(\gcd(a,b)=\gcd(b,a)\)

\(a=b\)\(\gcd(a,b)=a\)

\(a,b\) 同为偶数时,\(\gcd(a,b)=2*\gcd(\frac{a}{2},\frac{b}{2})\)

\(a\) 为偶数,\(b\) 为奇数时,\(\gcd(a,b)=\gcd(\frac{a}{2},b)\)

\(a\) 为奇数,\(b\) 为偶数时,\(\gcd(a,b)=\gcd(a,\frac{b}{2})\)

\(a,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);
}
posted @ 2022-05-03 16:27  Thunder_S  阅读(190)  评论(0编辑  收藏  举报