欧几里得(gcd)&& 扩展欧几里得(exgcd)
一.欧几里得(gcd)
1. 简介
欧几里得大家应该不陌生,就是求最大公约数的那个。
2. 实现
可以用辗转相除法:
gcd
(
a
,
b
)
=
gcd
(
b
,
a
%
b
)
\gcd(a,b)=\gcd(b,a\%b)
gcd(a,b)=gcd(b,a%b)
当 b = 0 时,返回 a 的值。
3. 具体代码
int gcd ( int a , int b )
{
if ( b == 0 )
return a ;
else
return gcd ( b , a % b );
}
二.扩展欧几里得(exgcd)
1. 简介
扩展欧几里得就是欧几里得的扩展版(这不是废话嘛),他有一个不定方程,很奇怪:
a
x
+
b
y
=
c
ax+by=c
ax+by=c
2. 证明
奇奇怪怪的,但我们把他与 gcd 联系起来时就不觉得奇怪了:
a
x
+
b
y
=
g
c
d
(
a
,
b
)
=
c
ax+by=gcd(a,b)=c
ax+by=gcd(a,b)=c
我们可以发现,通过上面 gcd 的公式,我们是不是可以转化一下不定方程?
a
x
+
b
y
=
b
x
+
(
a
%
b
)
y
ax+by=bx+(a\%b)y
ax+by=bx+(a%b)y
然后再化简:
a
x
+
b
y
=
b
x
+
(
a
%
b
)
y
a
x
+
b
y
=
b
x
+
(
a
−
⌊
a
b
⌋
b
)
y
a
x
+
b
y
=
b
x
+
a
y
−
⌊
a
b
⌋
b
y
a
x
+
b
y
=
a
y
+
b
(
x
−
⌊
a
b
⌋
y
)
ax+by=bx+(a\%b)y\\ ax+by=bx+(a-\left \lfloor \frac{a}{b} \right \rfloor b)y\\ ax+by=bx+ay-\left \lfloor \frac{a}{b} \right \rfloor by\\ ax+by=ay+b(x-\left \lfloor \frac{a}{b} \right \rfloor y)
ax+by=bx+(a%b)yax+by=bx+(a−⌊ba⌋b)yax+by=bx+ay−⌊ba⌋byax+by=ay+b(x−⌊ba⌋y)
到这里,我们发现:
x
=
y
y
=
x
−
⌊
a
b
⌋
y
x=y\\ y=x-\left \lfloor \frac{a}{b} \right \rfloor y
x=yy=x−⌊ba⌋y
而运用 gcd 的结论 , 可以求出 x=1,y=0 。所以不定式方程为:
a
x
+
b
y
=
1
ax+by=1
ax+by=1
3. CODE
void exgcd(int a,int b)
{
if(b==0)
{
x=1;
y=0;
return ;
}
exgcd(b,a%b);
int tot=x;
x=y;
y=tot-(a/b)*x;
}
三.求最大值y,最小值x
观察ax+by=c,可转换为a(x-b)+b(y+a)=c,即ax+by=a(x-b)+b(y+a)=c 。
所以,x减或加多少b都没影响,只需y等量加或减上a。那么,我们只需x%b(x>0,也就是减去了最大的b)就能求出x的最小值。
结论(x 为非0):
x
=
[
(
x
%
b
)
+
b
]
%
b
x=[(x\%b)+b]\%b
x=[(x%b)+b]%b
最小值求出来了,那最大值 y 呢?当 x 最小时,y 自然也最大了
注意:当求的是 ax + by = gcd × d = c ( d 属于整数集),min(x)=((x % b)×(d % b)+b) % b(因为开始 c mod 了gcd,再mod b是为了取d的最小值)
理由:y = ( ax - c ) / b (移项)
四.后记
你们都学会了吗?