引言
这个扩展欧几里得算法用的还是比较多的,而且也很实用,话不多说直接开始吧。
一、裴蜀定理
裴蜀定理:对于任意正整数
a
和
b
,一定存在非零整数
x
和
y
,使得
a
x
+
b
y
=
g
c
d
(
a
,
b
)
裴蜀定理:对于任意正整数a和b,一定存在非零整数x和y,使得ax+by=gcd(a,b)
裴蜀定理:对于任意正整数a和b,一定存在非零整数x和y,使得ax+by=gcd(a,b)
也就是说a和b能凑出来的最小正整数就是它们的最大公约数
二、扩展欧几里得算法模板
给出 a 和 b , 求满足 a x + b y = g c d ( a , b ) 中任一 x 和 y 的值 给出a和b,求满足ax+by=gcd(a,b)中任一x和y的值 给出a和b,求满足ax+by=gcd(a,b)中任一x和y的值
int exgcd(int a, int b, int& x, int& y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a%b, y, x);
y -= a / b * x;
return d;
}
三、公式推导
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)
当
b
为
0
,
g
c
d
(
a
,
b
)
=
a
,
a
x
+
y
∗
0
=
a
,
则一组解为
x
=
1
,
y
=
0
当b为0,gcd(a,b)=a,ax+y*0=a,则一组解为x=1,y=0
当b为0,gcd(a,b)=a,ax+y∗0=a,则一组解为x=1,y=0
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
m
o
d
b
)
,
a
m
o
d
b
=
a
−
(
a
b
)
∗
b
,
注:此处的
a
b
都为下取整,
gcd(a,b) = gcd(b,a \mod\ b),a\mod b=a-(\frac{a}{b})\ *\ b,注:此处的\frac{a}{b}都为下取整,
gcd(a,b)=gcd(b,amod b),amodb=a−(ba) ∗ b,注:此处的ba都为下取整,
则
b
y
+
(
a
m
o
d
b
)
x
=
d
,
b
y
+
(
a
−
(
a
b
)
∗
b
)
x
=
d
,
则by+(a\mod b)x=d,by+(a-(\frac{a}{b})*b)x=d,
则by+(amodb)x=d,by+(a−(ba)∗b)x=d,
则
a
x
+
b
(
y
−
(
a
b
)
∗
x
)
=
d
则ax+b(y-(\frac{a}{b})*x)=d
则ax+b(y−(ba)∗x)=d
四、例题
1.扩展欧几里得算法模板题
题目描述:
给定 n 对正整数 ai,bi,对于每对数,求出一组 xi,yi,使其满足 ai×xi+bi×yi=gcd(ai,bi)。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含两个整数 ai,bi。
输出格式
输出共 n 行,对于每组 ai,bi,求出一组满足条件的 xi,yi,每组结果占一行。
本题答案不唯一,输出任意满足条件的 xi,yi 均可。
数据范围
1≤n≤105,1≤ai,bi≤2×109
输入样例:
2
4 6
8 18
输出样例:
-1 1
-2 1
示例代码:
#include <cstdio>
#include <iostream>
using namespace std;
int exgcd(int a, int b, int& x, int& y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a%b, y, x);
y -= a / b * x;
return d;
}
int main()
{
int n;
scanf("%d", &n);
while(n--)
{
int a, b, x, y;
scanf("%d%d",&a, &b);
exgcd(a, b, x, y);
printf("%d %d\n", x, y);
}
return 0;
}
2.线性同余方程
题目描述:
给定 n 组数据 ai,bi,mi,对于每组数求出一个 xi,使其满足 ai×xi≡bi(modmi),如果无解则输出 impossible。
输入格式
第一行包含整数 n。
接下来 n 行,每行包含一组数据 ai,bi,mi。
输出格式
输出共 n 行,每组数据输出一个整数表示一个满足条件的 xi,如果无解则输出 impossible。
每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。
输出答案必须在 int 范围之内。
数据范围
1≤n≤105,1≤ai,bi,mi≤2×109
,输入样例:
2
2 3 6
4 3 5
输出样例:
impossible
-3
求
a
x
≡
b
(
m
o
d
m
)
,即
a
x
=
m
y
+
b
,
即
a
x
−
m
y
=
b
,
求ax \equiv b \pmod m,即ax=my+b,即ax-my=b,
求ax≡b(modm),即ax=my+b,即ax−my=b,
令
y
′
=
−
y
,
则
a
x
+
m
y
′
=
b
,
令y\prime =-y,则ax+my\prime=b,
令y′=−y,则ax+my′=b,
又存在
a
x
+
m
y
′
=
g
c
d
(
a
,
m
)
,
又存在ax+my\prime = gcd(a,m),
又存在ax+my′=gcd(a,m),
所以只要判断
b
是否为
g
c
d
(
a
,
m
)
的倍数即可判断是否存在,并且
r
e
s
=
b
g
c
d
(
a
,
m
)
∗
x
所以只要判断b是否为gcd(a,m)的倍数即可判断是否存在,并且res=\frac{b}{gcd(a,m)}*x
所以只要判断b是否为gcd(a,m)的倍数即可判断是否存在,并且res=gcd(a,m)b∗x
示例代码:
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
int exgcd(int a, int b, int& x, int& y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main()
{
int n;
scanf("%d", &n);
while(n--)
{
int a, b, m, x, y;
scanf("%d%d%d", &a, &b, &m);
int d = exgcd(a, m, x, y);
if(b % d == 0) printf("%lld\n", (LL)x * (b / d) % m);
else puts("impossible");
}
return 0;
}