本文参考自:https://www.cnblogs.com/zwfymqz/p/8425731.html
我们知道,中国剩余定理是用来解同余方程组
f
(
x
)
=
{
x
≡
c
1
(
m
o
d
m
1
)
x
≡
c
2
(
m
o
d
m
2
)
…
…
…
…
…
x
≡
c
r
(
m
o
d
m
r
)
f(x)=\left\{ \begin{aligned} x ≡ c_1(mod\ m_1)\\ x ≡ c_2(mod\ m_2)\\ ……………\\ x ≡ c_r(mod\ m_r) \end{aligned} \right.
f(x)=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧x≡c1(mod m1)x≡c2(mod m2)……………x≡cr(mod mr)
但是要求是
m
1
,
m
2
,
…
,
m
r
m_1,m_2,…,m_r
m1,m2,…,mr两两互质
如果他们不互质呢?
就要用到拓展中国剩余定理
首先我们先考虑如果同余方程只有两个式子的情况
x
≡
c
1
(
m
o
d
m
1
)
x
≡
c
2
(
m
o
d
m
2
)
将
这
两
个
式
子
变
形
x
=
c
1
+
m
1
k
x
=
c
2
+
m
2
k
联
立
c
1
+
m
1
k
=
c
2
+
m
2
k
移
项
m
1
k
=
c
2
−
c
1
+
m
2
k
x ≡ c_1(mod\ m_1)\\ x ≡ c_2(mod\ m_2)\\ 将这两个式子变形\\ x = c_1 + m_1k\\ x = c_2 + m_2k\\ 联立\\ c_1 + m_1k = c_2 + m_2k\\ 移项\\ m_1k = c_2 - c_1 + m_2k
x≡c1(mod m1)x≡c2(mod m2)将这两个式子变形x=c1+m1kx=c2+m2k联立c1+m1k=c2+m2k移项m1k=c2−c1+m2k
我们用(a,b)表示a,b的最大公约数
这里需要注意,这个方程有解的条件是
(m1,m2) | (c2 - c1),因为后面会用到
(
c
2
−
c
1
)
(
m
2
,
m
1
)
\frac{(c_2 - c_1)}{(m_2,m_1)}
(m2,m1)(c2−c1)这一项,如果不能整除的话肯定会出现小数
对于上面的方程,两边同时除(m1,m2)
m
1
k
1
(
m
1
,
m
2
)
=
c
2
−
c
1
(
m
1
,
m
2
)
+
m
2
k
2
(
m
1
,
m
2
)
\frac{m_1k_1}{(m_1,m_2)} = \frac{c_2 - c_1}{(m_1,m_2)} + \frac{m_2k_2}{(m_1,m_2)}
(m1,m2)m1k1=(m1,m2)c2−c1+(m1,m2)m2k2
m
1
(
m
1
,
m
2
)
k
1
=
c
2
−
c
1
(
m
1
,
m
2
)
+
m
2
(
m
1
,
m
2
)
k
2
\frac{m_1}{(m_1,m_2)}k_1 = \frac{c_2 - c_1}{(m_1,m_2)} + \frac{m_2}{(m_1,m_2)}k_2
(m1,m2)m1k1=(m1,m2)c2−c1+(m1,m2)m2k2
转换一下
m
1
(
m
1
,
m
2
)
k
1
=
c
2
−
c
1
(
m
1
,
m
2
)
(
m
o
d
m
2
(
m
1
,
m
2
)
)
\frac{m_1}{(m_1,m_2)}k_1 = \frac{c_2 - c_1}{(m_1,m_2)} (mod \frac {m_2}{(m_1,m_2)})
(m1,m2)m1k1=(m1,m2)c2−c1(mod(m1,m2)m2)
此时我们已经成功把k2消去了。
同余式两边同除
m
1
(
m
1
,
m
2
)
\frac{m_1}{(m_1,m_2)}
(m1,m2)m1
k
1
≡
i
n
v
(
m
1
(
m
1
,
m
2
)
,
m
2
(
m
1
,
m
2
)
)
∗
(
c
2
−
c
1
)
(
m
1
,
m
2
)
(
m
o
d
m
2
(
m
1
,
m
2
)
)
k_1 ≡ inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} (mod\ \frac{m_2}{(m_1,m_2)})
k1≡inv((m1,m2)m1,(m1,m2)m2)∗(m1,m2)(c2−c1)(mod (m1,m2)m2)
inv(a,b)表示a在模b意义下的逆元
k
1
≡
i
n
v
(
m
1
(
m
1
,
m
2
)
,
m
2
(
m
1
,
m
2
)
)
∗
(
c
2
−
c
1
)
(
m
1
,
m
2
)
+
m
2
(
m
1
,
m
2
)
∗
y
k_1 ≡ inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} + \frac{m_2}{(m_1,m_2)} * y
k1≡inv((m1,m2)m1,(m1,m2)m2)∗(m1,m2)(c2−c1)+(m1,m2)m2∗y
接下来怎么办呢?这个狮子已经化到最简了。。
不要忘了,我们刚开始还有两个式子。我们把k1代回去!
x
=
i
n
v
(
m
1
(
m
1
,
m
2
)
,
m
2
(
m
1
,
m
2
)
)
∗
(
c
2
−
c
1
)
(
m
1
,
m
2
)
∗
m
1
+
y
m
1
m
2
(
m
1
,
m
2
)
+
c
1
x = inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} * m_1 + y\frac{m_1m_2}{(m_1,m_2)} + c_1
x=inv((m1,m2)m1,(m1,m2)m2)∗(m1,m2)(c2−c1)∗m1+y(m1,m2)m1m2+c1
x
≡
i
n
v
(
m
1
(
m
1
,
m
2
)
,
m
2
(
m
1
,
m
2
)
)
∗
(
c
2
−
c
1
)
(
m
1
,
m
2
)
∗
m
1
+
c
1
(
m
o
d
m
1
m
2
(
m
1
,
m
2
)
)
x ≡ inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} * m_1 + c_1(mod \frac{m_1m_2}{(m_1,m_2)})
x≡inv((m1,m2)m1,(m1,m2)m2)∗(m1,m2)(c2−c1)∗m1+c1(mod(m1,m2)m1m2)
此时,整个式子中的元素我们已经就知道了
具体一点,这个式子可以看作
x ≡ c(mod m)
其中
c =
(
i
n
v
(
m
1
(
m
1
,
m
2
)
,
m
2
(
m
1
,
m
2
)
)
∗
(
c
2
−
c
1
)
(
m
1
,
m
2
)
)
(inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)})
(inv((m1,m2)m1,(m1,m2)m2)∗(m1,m2)(c2−c1)) %
m
2
(
m
1
,
m
2
)
∗
m
1
+
c
1
\frac{m_2}{(m_1,m_2)} * m_1 + c_1
(m1,m2)m2∗m1+c1
m
=
m
1
m
2
(
m
1
,
m
2
)
m = \frac{m_1m_2}{(m_1,m_2)}
m=(m1,m2)m1m2
推广一下
我们每次把两个同余式合并,求解之后得到一个新的同余式。在把新的同余式和其他的联立,最终就可以求出满足条件的解
int n;
ll m[maxn],c[maxn];
ll gcd(ll a,ll b){
return b==0 ? a:gcd(b,a%b);
}
ll mul(ll x,ll y,ll z){
ll sm = (ld)x/z*y;
return ((ull)x*y-(ull)sm*z+z)%z;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x = 1;
y = 0;
return a;
}
ll g = exgcd(b,a%b,y,x);
y -= a/b * x;
return g;
}
ll inv(ll a,ll b){
ll x,y;
ll g = exgcd(a,b,x,y);
ll tp = b/g;
x = (x%tp+tp)%tp;
return x;
}
ll excrt()
{
for(int i=2;i<=n;i++){
//取出m1,m2,c1,c2
ll m1 = m[i-1], m2 = m[i];
ll c2 = c[i], c1 = c[i - 1];
ll T = gcd(m1,m2);
//判断(m1,m2)|(c2-c1)
if((c2-c1)%T) return -1;
//m = (m1m2)/(m1,m2)
m[i] = m1/T*m2;
//c = (inv(……)……)
c[i] = mul(inv(m1/T,m2/T),(c2-c1)/T,(m2/T))*m1+c1;
c[i] = (c[i]%m[i]+m[i])%m[i];
}
return c[n];
}
纯模板题:https://www.luogu.org/problem/P4777
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<ctime>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100100;
ll m[maxn],c[maxn];
int n;
ll gcd(ll a,ll b){
return b==0 ? a:gcd(b,a%b);
}
ll mul(ll x,ll y,ll z){
ll sm = (ld)x/z*y;
return ((ull)x*y-(ull)sm*z+z)%z;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x = 1;
y = 0;
return a;
}
ll g = exgcd(b,a%b,y,x);
y -= a/b * x;
return g;
}
ll inv(ll a,ll b){
ll x,y;
ll g = exgcd(a,b,x,y);
ll tp = b/g;
x = (x%tp+tp)%tp;
return x;
}
ll excrt()
{
for(int i=2;i<=n;i++){
ll m1 = m[i-1], m2 = m[i];
ll c2 = c[i], c1 = c[i - 1];
ll T = gcd(m1,m2);
if((c2-c1)%T) return -1;
m[i] = m1/T*m2;
c[i] = mul(inv(m1/T,m2/T),(c2-c1)/T,(m2/T))*m1+c1;
c[i] = (c[i]%m[i]+m[i])%m[i];
}
return c[n];
}
int main(void)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&m[i],&c[i]);
ll ans = excrt();
if(ans!=-1) printf("%lld\n",ans);
return 0;
}