裴蜀定理
1 定理
裴蜀定理:
设 a , b a, b a,b是不全为零的整数,则一定存在整数 x , y x, y x,y, 使得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)
换句话说,若
a
,
b
a, b
a,b是不全为零的整数,则
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)一定存在整数解
x
,
y
x, y
x,y。
证明过程在上面的链接中。
求出整数解的过程就是扩展欧几里得算法
2 推论
令
d
=
g
c
d
(
a
,
b
)
d=gcd(a,b)
d=gcd(a,b),由于
a
a
a和
b
b
b分别去掉最大公因数
d
d
d后,二者不再有公因子,即
a
d
\frac{a}{d}
da和
b
d
\frac{b}{d}
db是互质的
令
a
′
=
a
d
a'=\frac{a}{d}
a′=da,
b
′
=
b
d
b'=\frac{b}{d}
b′=db,
a
x
+
b
y
=
d
ax+by=d
ax+by=d左右同除
d
d
d,得到如下推论:
推论1:
若 a ′ a' a′和 b ′ b' b′互质,则方程 a ′ x + b ′ y = 1 a'x+b'y=1 a′x+b′y=1有整数解。
此外还可证明推论2:
若方程 a ′ x + b ′ y = 1 a'x+b'y=1 a′x+b′y=1有整数解,则 a ′ a' a′和 b ′ b' b′互质
反证:若
a
′
a'
a′和
b
′
b'
b′不互质,则有
a
′
=
g
c
d
(
a
′
,
b
′
)
∗
p
a'=gcd(a',b')*p
a′=gcd(a′,b′)∗p,
b
′
=
g
c
d
(
a
′
,
b
′
)
∗
q
b'=gcd(a',b')*q
b′=gcd(a′,b′)∗q,此处
p
,
q
p,q
p,q为互质的整数。
代入方程中,得到:
g
c
d
(
a
′
,
b
′
)
∗
p
∗
x
+
g
c
d
(
a
′
,
b
′
)
∗
q
∗
y
=
1
gcd(a',b')*p*x+gcd(a',b')*q*y=1
gcd(a′,b′)∗p∗x+gcd(a′,b′)∗q∗y=1
左右同除
g
c
d
(
a
′
,
b
′
)
gcd(a',b')
gcd(a′,b′):
p
∗
x
+
q
∗
y
=
1
g
c
d
(
a
′
,
b
′
)
p*x+q*y=\frac{1}{gcd(a',b')}
p∗x+q∗y=gcd(a′,b′)1
由于
a
′
a'
a′和
b
′
b'
b′不互质,则
g
c
d
(
a
′
,
b
′
)
>
1
gcd(a',b')>1
gcd(a′,b′)>1,
1
g
c
d
(
a
′
,
b
′
)
\frac{1}{gcd(a',b')}
gcd(a′,b′)1是小数,所以
x
x
x和
y
y
y不可能是整数,方程
a
′
x
+
b
′
y
=
1
a'x+b'y=1
a′x+b′y=1没有整数解,矛盾。
结合推论1和推论2,可得到裴蜀定理推论:
a ′ a' a′和 b ′ b' b′互质的充要条件是方程 a ′ x + b ′ y = 1 a'x+b'y=1 a′x+b′y=1有整数解
3 判断不定方程是否有整数解
a x + b y = z ax+by=z ax+by=z有整数解的充要条件是 g c d ( a , b ) ∣ z gcd(a,b)|z gcd(a,b)∣z
1、若
z
z
z能整除
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b),则
a
x
+
b
y
=
z
ax+by=z
ax+by=z有整数解
设
z
=
k
∗
g
c
d
(
a
,
b
)
z=k*gcd(a,b)
z=k∗gcd(a,b)
由裴蜀定理知存在整数解
x
′
,
y
′
x',y'
x′,y′使得
a
x
′
+
b
y
′
=
g
c
d
(
a
,
b
)
ax'+by'=gcd(a,b)
ax′+by′=gcd(a,b)
则
a
x
+
b
y
=
z
ax+by=z
ax+by=z相当于
a
k
x
′
+
b
k
y
′
=
k
∗
g
c
d
(
a
,
b
)
akx'+bky'=k*gcd(a,b)
akx′+bky′=k∗gcd(a,b)
整数解是
x
=
k
x
′
x=kx'
x=kx′和
y
=
k
y
′
y=ky'
y=ky′
2、若
a
x
+
b
y
=
z
ax+by=z
ax+by=z有整数解,则
z
z
z能整除
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b)
证明类似推论2
反证:若
z
z
z不能整除
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b)
将
a
x
+
b
y
=
z
ax+by=z
ax+by=z两边同除
g
c
d
(
a
,
b
)
gcd(a,b)
gcd(a,b)
有
a
′
x
+
b
′
y
=
z
g
c
d
(
a
,
b
)
a'x+b'y=\frac{z}{gcd(a,b)}
a′x+b′y=gcd(a,b)z,其中
a
′
=
a
g
c
d
(
a
,
b
)
a'=\frac{a}{gcd(a,b)}
a′=gcd(a,b)a和
b
′
=
b
g
c
d
(
a
,
b
)
b'=\frac{b}{gcd(a,b)}
b′=gcd(a,b)b是互质的整数
由于
z
g
c
d
(
a
,
b
)
\frac{z}{gcd(a,b)}
gcd(a,b)z是小数,所以
x
x
x和
y
y
y不可能是整数,方程
a
x
+
b
y
=
z
ax+by=z
ax+by=z没有整数解,矛盾。
4 推广到n元
对不定方程 a 1 x 1 + a 2 x 2 + . . . + a n x n = z a_1x_1+a_2x_2+...+a_nx_n=z a1x1+a2x2+...+anxn=z,满足 g c d ( a 1 , a 2 , . . . , a n ) ∣ z gcd(a_1,a_2,...,a_n)|z gcd(a1,a2,...,an)∣z时,方程才有整数解
g c d ( a 1 , a 2 , . . . , a n ) = 1 gcd(a_1,a_2,...,a_n)=1 gcd(a1,a2,...,an)=1的充要条件是不定方程 a 1 x 1 + a 2 x 2 + . . . + a n x n = 1 a_1x_1+a_2x_2+...+a_nx_n=1 a1x1+a2x2+...+anxn=1有整数解
扩展欧几里得
利用辗转相除法可以顺便得到x和y。
辗转相除法过程如下:
int exgcd(int a, int b) {
if(!b) {
return a;
}
else {
return exgcd(b, a % b);
}
}
当b=0时,可以看出ax+by=gcd(a,b)的一组解是x=1,y=0。于是有:
if(!b) {
x = 1, y = 0;
return a;
}
在进行辗转时,
a
′
=
b
a'=b
a′=b,
b
′
=
a
%
b
b'=a\%b
b′=a%b,带入
a
′
x
+
b
′
y
=
d
a'x+b'y=d
a′x+b′y=d中可得
b
x
+
(
a
%
b
)
y
=
d
bx+(a\%b)y=d
bx+(a%b)y=d。
a
%
b
a\%b
a%b可以写成
a
−
⌊
a
/
b
⌋
∗
b
a-\lfloor a/b \rfloor * b
a−⌊a/b⌋∗b
所以有
b
x
+
(
a
−
⌊
a
/
b
⌋
b
)
y
=
d
bx+(a-\lfloor a/b \rfloor b)y=d
bx+(a−⌊a/b⌋b)y=d。
我们想知道a和b的整数解x和y,因此要提出a和b,a和b的系数就是下一轮的x’和y’。
上式变为
a
y
+
b
(
x
−
⌊
a
/
b
⌋
y
)
=
d
ay+b(x-\lfloor a/b \rfloor y)=d
ay+b(x−⌊a/b⌋y)=d
于是有
x
′
=
y
,
y
′
=
(
x
−
⌊
a
/
b
⌋
y
)
x'=y, y'=(x-\lfloor a/b \rfloor y)
x′=y,y′=(x−⌊a/b⌋y)
else {
int d = exgcd(b, a % b, x, y);
int tmp = x;
x = y;
y = tmp - a / b * y;
return d;
}
为了便于书写,可以交换递归时x和y的位置,省掉中间变量tmp
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
else {
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
}
该题代码如下
#include <iostream>
using namespace std;
int n, a, b, x, y;
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
else {
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
}
int main() {
scanf("%d", &n);
while(n -- ) {
scanf("%d%d", &a, &b);
exgcd(a, b, x, y);
printf("%d %d\n", x, y);
}
return 0;
}