中国剩余定理总是不太熟练,写一篇 Blog B l o g 复习一下好了。
中国剩余定理
有 n n 个线性同余方程:, mi m i 都互质,求解这个线性同余方程组
使用中国剩余定理( Chineseremaindertheorem C h i n e s e r e m a i n d e r t h e o r e m , crt c r t )来解决,它是一种构造方法,本质思想是每项只对自己有贡献.
令 M=∏ni=1mi M = ∏ i = 1 n m i ,答案为:
其中 Mi M i 表示 Mmi M m i , Ni N i 表示 Mi M i 在 modmi m o d m i 意义下的逆元.
大概写起来是这样的,比较简单
int Crt(int n, int * m, int * a) {
int ans = 0, M = 1;
for(int i = 1; i <= n; i ++) M *= m[i];
for(int i = 1; i <= n; i ++) {
int Mi = M / m[i];
int Ni = inv(Mi, m[i]);
(ans += Mi * Ni % M * a[i] % M) %= M;
}
return (ans + M) % M;
}
扩展中国剩余定理
有 n n 个线性同余方程:,不保证 mi m i 都互质,求解这个线性同余方程组
使用扩展中国剩余定理( ExtendedChineseRemainderTheorem E x t e n d e d C h i n e s e R e m a i n d e r T h e o r e m , crt c r t )解决, Scαpe S c α p e 鸽鸽 称其为增量法.
考虑每次如何把两个线性同余方程合并。
假设有两个方程,
x≡a(modb)
x
≡
a
(
m
o
d
b
)
,
x≡c(modd)
x
≡
c
(
m
o
d
d
)
由于第一个式子得:
x=bt+a
x
=
b
t
+
a
.
于是得到:
bt+a≡c(modd)
b
t
+
a
≡
c
(
m
o
d
d
)
bt≡c−a(modd)
b
t
≡
c
−
a
(
m
o
d
d
)
然后这是经典的同余方程,直接使用
exgcd
e
x
g
c
d
求解.
解出:
t≡t0(moddgcd(b,d))
t
≡
t
0
(
m
o
d
d
g
c
d
(
b
,
d
)
)
于是得到
x=bt+a(moddgcd(b,d))
x
=
b
t
+
a
(
m
o
d
d
g
c
d
(
b
,
d
)
)
于是每次我们两两合并,合并 n−1 n − 1 次,就完事了.
LL exgcd(LL a, LL b, LL &x, LL &y, LL &g) {
if(!b) x = 1, y = 0, g = a;
else exgcd(b, a % b, y, x, g), y -= x * (a / b);
}
LL excrt(int n, LL * m, LL * a) { //x = a[i] (mod m[i])
LL c = a[1], d = m[1], p, q, g;
for(int i = 2; i <= n; i ++) {
exgcd(d, m[i], p, q, g);
LL tmp = a[i] - c;
if(tmp % g != 0) return ; //No result
p *= tmp / g;
p = (p % (m[i] / g) + (m[i] / g)) % (m[i] / g);
c += p * d;
d = d / g * m[i];
c %= d;
}
return (c % d + d) % d;
}