前置知识:
1.给予两个整数a,b。必存在整数x,y使得ax+by=gcd(a,b)。
2.0和任何一个数的最大公约数是这个数的本身。
3.辗转相除:
g c d ( a , b ) = g c d ( b , a m o d b ) ∵ a m o d b = r ∴ a = k b ∗ r ; 设 g c d ( a , b ) = c ∴ a ∣ c , b ∣ c ∴ b k ∣ c ∵ a ∣ c ∴ ( b k + r ) ∣ c , r ∣ c 由 此 得 出 : g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a,b) = gcd(b, a \ mod \ b) \\ \because a \ mod \ b = r \therefore a = kb*r; \\ 设gcd(a,b) = c \therefore a|c, b|c\\ \therefore bk|c \\ \because a|c \ \therefore (bk+r)|c, r|c \\ 由此得出:gcd(a,b) = gcd(b, a \ mod \ b) gcd(a,b)=gcd(b,a mod b)∵a mod b=r∴a=kb∗r;设gcd(a,b)=c∴a∣c,b∣c∴bk∣c∵a∣c ∴(bk+r)∣c,r∣c由此得出:gcd(a,b)=gcd(b,a mod b)
推理:
1.当b=0,gcd(a,b) = a。所以x = 1, y = 0 --> ax=a;
2.当 a != 0, b != 0:
由辗转相除法可知:
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
m
o
d
b
)
∴
a
x
+
b
y
=
b
x
′
+
(
a
m
o
d
b
)
y
′
∴
a
x
+
b
y
=
b
x
′
+
(
a
−
a
/
b
∗
b
)
y
′
∴
a
x
+
b
y
=
a
y
′
+
b
(
x
′
−
a
/
b
∗
y
′
)
对
比
系
数
:
x
=
y
′
y
=
x
′
−
a
/
b
∗
y
′
gcd(a, b) = gcd(b, a\ mod \ b) \\ \therefore ax+by = bx' + (a \ mod \ b)y'\\ \therefore ax+by = bx'+(a-a/b*b)y'\\ \therefore ax+by = ay'+b(x' - a/b*y') \\对比系数: x = y' \ \ \ y = x'-a/b*y'
gcd(a,b)=gcd(b,a mod b)∴ax+by=bx′+(a mod b)y′∴ax+by=bx′+(a−a/b∗b)y′∴ax+by=ay′+b(x′−a/b∗y′)对比系数:x=y′ y=x′−a/b∗y′
也就是说,如果我们知道了x’,y’就可以倒退得到x, y然而由辗转相除可知,经gcd(a,b) = gcd(b, a%b)如此反复b将变为0,然后利用b = 0时,x = 1,y = 0逐步倒推,最终得到ax+by=gcd(a, b)的一组解。
代码:
int exGcd(int a, int b, int &x, int &y)
{
if(b == 0)
{
x = 1;
y = 0;
return a;
}
int g = exGcd(b, a % b, x, y);
int temp = x;
x = y;
y = temp - a / b * y;
return g;
}
例题
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int exgcd(int a, int b, int& xx, int& yy)
{
if (!b)
{
xx = 1, yy = 0;
return a;
}
int g = exgcd(b, a % b, yy, xx);
yy -= a / b * xx;
return g;
}
void solve()
{
int n, d, x, y;
cin >> n >> d >> x >> y;
int xx, yy;
int tmp = exgcd(n, d, xx, yy);
if ((y - x) % tmp)
{
cout << "Impossible" << endl;
return;
}
yy *= (y - x) / tmp;
n /= tmp;
cout << (yy % n + n) % n << endl;
}
signed main()
{
IOS;
int T;
cin >> T;
while (T--)
solve();
return 0;
}
如何根据已经求得的一组整数解求得其他的整数解:
x, y是我们根据ax+by=gcd(a,b)得一组通解,现在我们设新得解为x‘,y’;那么x’ = x+s1, y‘ = y-s2,则有
a
(
x
+
s
1
)
+
b
(
y
−
s
2
)
=
g
c
d
(
a
,
b
)
∴
a
x
+
a
s
1
+
b
y
−
b
s
2
=
g
c
d
(
a
,
b
)
∵
a
x
+
b
y
=
g
c
d
(
a
,
b
)
∴
a
s
1
=
b
s
2
a(x+s_1)+b(y-s_2) = gcd(a,b) \\ \therefore ax+as_1+by-bs_2 = gcd(a,b) \\ \because ax+by = gcd(a, b)\\ \therefore as_1 = bs_2
a(x+s1)+b(y−s2)=gcd(a,b)∴ax+as1+by−bs2=gcd(a,b)∵ax+by=gcd(a,b)∴as1=bs2
让a,b同时除以一个较大的数(即a和b的最大公约数)
s
1
s
2
=
b
g
c
d
(
a
,
b
)
a
g
c
d
(
a
,
b
)
∴
s
1
=
k
∗
b
g
c
d
(
a
,
b
)
,
s
2
=
k
∗
a
g
c
d
(
a
,
b
)
\frac{s_1}{s_2} = \frac{\frac{b}{gcd(a,b)}}{\frac{a}{gcd(a, b)}}\\ \therefore s_1 = k*\frac{b}{gcd(a,b)}, s_2 = k*\frac{a}{gcd(a, b)}
s2s1=gcd(a,b)agcd(a,b)b∴s1=k∗gcd(a,b)b,s2=k∗gcd(a,b)a
由此我们可以得到ax+by = gcd(a, b)
x
=
x
0
+
k
∗
b
g
c
d
(
a
,
b
)
y
=
y
0
−
k
∗
a
g
c
d
(
a
,
b
)
x
0
,
y
0
是
E
X
G
C
D
求
得
的
一
组
解
x = x_0+k*\frac{b}{gcd(a,b)}\\ y= y_0-k*\frac{a}{gcd(a,b)}\\ x_0,y_0是EXGCD求得的一组解
x=x0+k∗gcd(a,b)by=y0−k∗gcd(a,b)ax0,y0是EXGCD求得的一组解
其他:
以上是求ax+by=gcd的通解的推导,如果我们想求ax+by=c的通解,首先我们要判断c是否能整除gcd(a, b),如果不能整除代表此式子无解。
然后我们根据exgcd求出ax+by=gcd(a,b)一组解x’, y’,然后我们再求出原式的一组解
x
=
x
′
∗
c
g
c
d
(
a
,
b
)
∗
k
∗
b
g
c
d
(
a
,
b
)
y
=
y
′
∗
c
g
c
d
(
a
,
b
)
∗
k
∗
a
g
c
d
(
a
,
b
)
x = x'*\frac{c}{gcd(a,b)}*k*\frac{b}{gcd(a,b)}\\y=y'*\frac{c}{gcd(a,b)}*k*\frac{a}{gcd(a,b)}
x=x′∗gcd(a,b)c∗k∗gcd(a,b)by=y′∗gcd(a,b)c∗k∗gcd(a,b)a