对模线性方程 ax = b (mod m),有 ax = k*m + b,其中 k 是整数。
移项后有 ax - km = b,转化到了 EXGCD 的解法。
若有模线性方程组如下:
x=b1(modm1)
x
=
b
1
(
m
o
d
m
1
)
x=b2(modm2)
x
=
b
2
(
m
o
d
m
2
)
x=b3(modm3)
x
=
b
3
(
m
o
d
m
3
)
…………
x=bk(modmk)
x
=
b
k
(
m
o
d
m
k
)
需要我们解出一个
x
x
方法一:
我们取前两个式子,则有
x=k2∗m2+a2
x
=
k
2
∗
m
2
+
a
2
相应变动后有
m1∗k1−m2∗k2=a2−a1
m
1
∗
k
1
−
m
2
∗
k
2
=
a
2
−
a
1
其中
m1,m2,a2,a1
m
1
,
m
2
,
a
2
,
a
1
是已知的,由 exgcd 能够得到一组特解
k1,k2
k
1
,
k
2
.
k1
k
1
带回第一个式子能得到一个特解 X。
那么其他的解
x=X+k∗lcm(m1,m2)
x
=
X
+
k
∗
l
c
m
(
m
1
,
m
2
)
,k是自然数。
变形后可以得到
x=X(modlcm(m1,m2))
x
=
X
(
m
o
d
l
c
m
(
m
1
,
m
2
)
)
再和
x=b3(modm3)
x
=
b
3
(
m
o
d
m
3
)
继续上述过程,可以得到所有方程的解。
方法二:
中国剩余定理:
有一次同余方程组如下:
x=b1(modm1)
x
=
b
1
(
m
o
d
m
1
)
x=b2(modm2)
x
=
b
2
(
m
o
d
m
2
)
x=b3(modm3)
x
=
b
3
(
m
o
d
m
3
)
….
x=bk(modmk)
x
=
b
k
(
m
o
d
m
k
)
设 m1,m2,m3...mk m 1 , m 2 , m 3 . . . m k 是两两互素的正整数,对于任意的 b1,b2,b3...bk b 1 , b 2 , b 3 . . . b k ,一次同余方程组必定有解,且只有一组解。
令
M=m1∗m2∗m3∗...∗mk
M
=
m
1
∗
m
2
∗
m
3
∗
.
.
.
∗
m
k
,
Mi=Mmi
M
i
=
M
m
i
,
有
Mi−1
M
i
−
1
满足
Mi−1∗Mi=1(mod(mi))
M
i
−
1
∗
M
i
=
1
(
m
o
d
(
m
i
)
)
,
则同余方程组的解为
x=(∑Mi∗Mi−1∗bi)(modM)
x
=
(
∑
M
i
∗
M
i
−
1
∗
b
i
)
(
m
o
d
M
)
方法一代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
ll mr[105];
ll ar[105];
ll exgcd (ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
ll r = exgcd(b, a%b, x, y);
ll t = x;
x = y;
y = t - a/b*y;
return r;
}
ll solve (int n) {
ll M = mr[1], A = ar[1], x, y;
for (int i = 2; i <= n; i++) {
ll d = exgcd(M, mr[i], x, y);
if (abs(A - ar[i]) % d != 0) {
return -1;
}
x = (A - ar[i]) / d * x;
ll tmp = ar[i] / d;
x = x % tmp;
A = x*M + A;
M = M*ar[i]/d;
A = A % M;
if (A < 0) {
A += M;
}
}
if (A == 0) {
return M;
}
else {
return (A%M+M)%M;
}
}
方法二代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
ll mr[105]; //模
ll ar[105]; //余数
ll exgcd (ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
ll r = exgcd(b, a%b, x, y);
ll t = x;
x = y;
y = t - a/b*y;
return r;
}
ll solve (int n) {
ll ans = 0, M = 1;
for (int i = 1; i < n; i++) {
M *= ar[i];
}
for (int i = 1; i <= n; i++) {
ll tmp = M / mr[i];
ll x, y;
exgcd(tmp, mr[i], x, y);
ans = (ans + tmp*x*ar[i]) % M;
}
return (ans%M+M)%M;
}