前言
由于复习CSP,我的blog咕咕咕了一个多月。大有洛谷的风范 今天,我来写一下自己学习gcd及exgcd的感受。
详解gcd及exgcd
gcd
什么是gcd
gcd指的是Greatest Common Divisor,就是两个数的最大公因数。
通俗来讲, gcd ( a , b ) \gcd(a,b) gcd(a,b)就是最大化一个 A n s Ans Ans,使得 A n s ∣ a , A n s ∣ b Ans|a\\,Ans|b Ans∣a,Ans∣b。
举个例子:
20 20 20的因数有 1 , 2 , 4 , 5 , 10 , 20 1,2,4,5,10,20 1,2,4,5,10,20。
15 15 15的因数有 1 , 3 , 5 , 15 1,3,5,15 1,3,5,15。
所以 gcd ( 20 , 15 ) = 5 \gcd(20,15)=5 gcd(20,15)=5。
如何求gcd
想必各位在高中都学过辗转相除法和更相减损之术,这里只讲辗转相除法。
辗转相除法
首先不妨设
x
≤
y
x\le y
x≤y,则
gcd
(
x
,
y
)
=
gcd
(
x
,
x
+
y
)
=
gcd
(
x
,
y
−
x
)
\gcd(x,y)=\gcd(x,x+y)=\gcd(x,y-x)
gcd(x,y)=gcd(x,x+y)=gcd(x,y−x),所以
gcd
(
x
,
y
)
=
g
c
d
(
y
m
o
d
x
,
x
)
\gcd(x, y) = gcd(y \mod x, x)
gcd(x,y)=gcd(ymodx,x),因此可以递归求解。
复杂度证明:因为
y
m
o
d
x
≤
x
,
x
≤
y
y \mod x \le x ,x \le y
ymodx≤x,x≤y,所以
y
m
o
d
x
<
y
/
2
y \mod x < y / 2
ymodx<y/2。因此在最坏情况下为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
另外说一句:最坏的情况恰好是斐波那契额数列的相邻两个(细思极恐)
代码
int gcd(int a,int b)
{
if(!b)
{
return a;
}
return gcd(b,a%b);
}
exgcd
啥是exgcd
exgcd可以概括成求形如
a x + b y = c ax+by=c ax+by=c
的方程。
当存在 gcd ( a , b ) ∣ c \gcd(a,b)|c gcd(a,b)∣c时,存在解。
也就是说,这个exgcd可以用来求解方程 a x + b y = gcd ( a , b ) ax +by = \gcd(a, b) ax+by=gcd(a,b)
exgcd的证明
我们命 a = b , b = a m o d b a=b, b=a \mod b a=b,b=amodb,则有方程 b × x 1 + ( a m o d b ) × y 1 = g c d ( b , a m o d b ) b \times x1 +(a \mod b) \times y1 = gcd(b, a \mod b) b×x1+(amodb)×y1=gcd(b,amodb)
又因为 gcd ( a , b ) = gcd ( a m o d b ) \gcd(a, b) = \gcd(a \mod b) gcd(a,b)=gcd(amodb),且 a m o d b = a − b × ⌊ a / b ⌋ a\mod b = a - b \times \lfloor a / b \rfloor amodb=a−b×⌊a/b⌋
则 b × x 1 + ( a − b ∗ ⌊ a / b ⌋ ) × y 1 = gcd ( a , b ) b \times x1 + (a - b * \lfloor a / b \rfloor ) \times y1 =\gcd(a, b) b×x1+(a−b∗⌊a/b⌋)×y1=gcd(a,b)
整理得: a × y 1 + b ∗ × ( x 1 − ⌊ a / b ⌋ × y 1 ) = gcd ( a , b ) a \times y1 +b *\times (x1 -\lfloor a / b \rfloor \times y1) = \gcd(a, b) a×y1+b∗×(x1−⌊a/b⌋×y1)=gcd(a,b)
所以原方程中: x = y 1 , y = x 1 − ⌊ a / b ⌋ × y 1 x = y1, y = x1 - \lfloor a / b\rfloor \times y1 x=y1,y=x1−⌊a/b⌋×y1。于是我们只要递归求出 x 1 , y 1 x1, y1 x1,y1就能求出 x , y x, y x,y。
代码
void exgcd(ll a, ll b, ll& x, ll& y, ll& c)
{
if(!b)
{
y=0;
x=1;
c=a;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}