中国剩余定理:
仅供自己复习时查看一下大佬笔记,详细学习过程在大佬的博客。
学习连接:https://www.cnblogs.com/MashiroSky/p/5918158.html
拓展中国剩余定理:
中国剩余定理在求解同余方程组的时候,要求模数之间是互质的,那么假如模数没有说明一定是互质的,这时就要用到了我们的拓展中国剩余定理(
e
x
c
r
t
excrt
excrt),拓展中国剩余定理其实和中国剩余定理联系不大,我觉得是因为它是用
e
x
g
c
d
exgcd
exgcd退出,并且与其联系紧密所以叫这个名字。
同余方程组:
{
x
≡
r
1
(
m
o
d
m
1
)
x
≡
r
2
(
m
o
d
m
2
)
.
.
x
≡
r
n
(
m
o
d
m
n
)
\begin{cases}x \equiv r_1\ (mod\ m_1) \\x \equiv r_2\ (mod\ m_2) \\..\\x \equiv r_n\ (mod\ m_n) \\ \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡r1 (mod m1)x≡r2 (mod m2)..x≡rn (mod mn)
考虑最开始的两个式子
{
x
≡
r
1
(
m
o
d
m
1
)
x
≡
r
2
(
m
o
d
m
2
)
\begin{cases}x \equiv r_1\ (mod\ m_1) \\x \equiv r_2\ (mod\ m_2) \end{cases}
{x≡r1 (mod m1)x≡r2 (mod m2)
即
x
=
r
1
+
k
1
∗
m
1
x = r_1 +k_1 * m_1
x=r1+k1∗m1,
x
=
r
2
+
k
2
∗
m
2
x = r_2 + k_2 * m_2
x=r2+k2∗m2,得
r
1
+
k
1
∗
m
1
=
r
2
+
k
2
∗
m
2
r_1 + k_1*m_1 = r_2 + k_2*m_2
r1+k1∗m1=r2+k2∗m2,移项的,
r
2
−
r
1
=
k
1
∗
m
1
+
(
−
k
2
)
∗
m
2
=
k
1
∗
m
1
+
k
2
∗
m
2
r_2 - r_1 = k_1*m_1 + (-k_2)*m_2 = k_1 * m_1 + k_2 * m_2
r2−r1=k1∗m1+(−k2)∗m2=k1∗m1+k2∗m2,这样这个式子就变成类似
a
x
+
b
y
=
c
ax + by = c
ax+by=c的形式了,于是我们求
K
1
∗
m
1
+
K
2
∗
m
2
=
g
c
d
(
m
1
,
m
2
)
K_1*m_1+K_2 * m_2 = gcd(m1,m2)
K1∗m1+K2∗m2=gcd(m1,m2),得到
K
1
K_1
K1后两边同时乘上
(
r
2
−
r
1
)
g
c
d
(
m
1
,
m
2
)
\frac {(r2 - r1)}{gcd(m_1,m_2)}
gcd(m1,m2)(r2−r1),可得
k
1
=
K
1
∗
(
r
2
−
r
1
)
g
c
d
(
m
1
,
m
2
)
k_1 = K_1 * \frac {(r2 - r1)}{gcd(m_1,m_2)}
k1=K1∗gcd(m1,m2)(r2−r1),这样把
k
1
k_1
k1在转化为最小的正数解之后,就可以用得到一个特解
x
∗
=
k
1
∗
m
1
+
r
1
x^* = k_1 * m_1 + r_1
x∗=k1∗m1+r1,怎么通过这个特解去获得一个同余方程呢,观察前面的式子
{
x
=
r
1
+
K
1
∗
(
r
2
−
r
1
)
g
c
d
(
m
1
,
m
2
)
∗
m
1
x
=
r
2
+
K
2
∗
(
r
2
−
r
1
)
g
c
d
(
m
1
,
m
2
)
∗
m
2
\begin{cases}x = r_1 + K_1 * \frac {(r2 - r1)}{gcd(m_1,m_2)} * m_1\\ x = r_2 + K_2 * \frac {(r2 - r1)}{gcd(m_1,m_2)} * m_2 \end{cases}
{x=r1+K1∗gcd(m1,m2)(r2−r1)∗m1x=r2+K2∗gcd(m1,m2)(r2−r1)∗m2
可以看到任意两个解之间的差值一定是
m
1
∗
m
2
g
c
d
(
m
1
,
m
2
)
\frac {m_1 * m_2}{gcd(m1,m2)}
gcd(m1,m2)m1∗m2的倍数,也就是我们的特解
x
∗
+
t
∗
l
c
m
(
m
1
,
m
2
)
=
x
(
通
解
)
x^* + t * lcm(m1,m2) = x(通解)
x∗+t∗lcm(m1,m2)=x(通解),到此也就能看出新的同余方程就是
x
≡
x
∗
(
m
o
d
l
c
m
(
m
1
,
m
2
)
)
x \equiv x^*\ (mod\ lcm(m1,m2))
x≡x∗ (mod lcm(m1,m2))。
所以对于n组方程我们只需要不断两两进行合并,更新合并出的方程组的对应的值,合并n-1次就可以得到一个最终的同余方程,最后的答案即为我们求得。
一些具体实现细节,需要结合代码加深理解。
例题:POJ2891 模板题
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
#define int long long
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int MAXN = 1e5 + 7;
int n;
int mod[MAXN],r[MAXN];//分别代表模数数组 和 余数数组
int exgcd(int a,int b,int &x,int &y) {
if(b == 0) {
x = 1; y = 0;
return a;
}
else {
int res = exgcd(b,a%b,x,y);
ll t = x;
x = y;
y = t - a / b * y;
return res;
}
}
int excrt() {//就是一个不断合并并且更新新的参数的过程
int MOD = mod[1],R = r[1],x,y;
for(int i = 2;i <= n;i ++) {
int g = exgcd(MOD,mod[i],x,y);
if((r[i] - R) % g != 0) return -1;//同余方程组无解
x = x * (r[i] - R) / g;
x = (x % (mod[i] / g) + (mod[i] / g)) % (mod[i] / g);//得到最小的解
R = x * MOD + R;
MOD = MOD / g * mod[i];//合并之后的模数 应该是lcm
R = R % MOD;//重新取一遍得到合并后的新的同余方程
}
return (R % MOD + MOD) % MOD;
}
signed main() {
while(~scanf("%lld",&n)) {
for(int i = 1;i <= n;i ++) {
scanf("%lld%lld",&mod[i],&r[i]);
}
int ans = excrt();
printf("%lld\n",ans);
}
}