中国剩余定理(crt)
[用途]
求方程组中最小的非负整数解X
X
≡
{
a
1
(
m
o
d
m
1
)
a
2
(
m
o
d
m
2
)
.
.
.
a
n
(
m
o
d
m
n
)
X\ \equiv\left\{\begin{array}{cc} a_{1} \quad (mod \quad m_{1})\\ a_{2} \quad (mod \quad m_{2})\\ ...\\ a_{n} \quad (mod \quad m_{n}) \end{array}\right.
X ≡⎩⎪⎪⎨⎪⎪⎧a1(modm1)a2(modm2)...an(modmn)
其中
m
i
,
m
j
m_{i},m_{j}
mi,mj两两互素
[引入]
韩信点兵:
韩信带1500名兵士打仗,战死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韩信很快说出人数:1049。
即
X
≡
{
2
(
m
o
d
3
)
4
(
m
o
d
5
)
.
.
.
6
(
m
o
d
7
)
X\ \equiv\left\{\begin{array}{cc} 2 \quad (mod \quad 3)\\ 4 \quad (mod \quad 5)\\ ...\\ 6 \quad (mod \quad7) \end{array}\right.
X ≡⎩⎪⎪⎨⎪⎪⎧2(mod3)4(mod5)...6(mod7)
解得 X = 1049 X=1049 X=1049
[结论]
X
=
∑
1
n
(
a
i
t
i
M
i
)
(
m
o
d
L
c
m
)
X=\sum_{1}^{n}(a_{i}t_{i}M_{i}) \quad (mod \quad Lcm)
X=∑1n(aitiMi)(modLcm)
其中:
最小公倍数
L
c
m
=
m
1
m
2
.
.
.
m
n
Lcm=m_{1}m_{2}...m_{n}
Lcm=m1m2...mn,因为
m
i
,
m
j
m_{i},m_{j}
mi,mj两两互素
M
i
=
L
c
m
/
m
i
M_{i}=Lcm/m_{i}
Mi=Lcm/mi
t
i
ti
ti 为
M
i
M_{i}
Mi 模
m
i
m_{i}
mi意义下的乘法逆元
[证明]
其中的
M
M
M就是
L
c
m
Lcm
Lcm
百度百科
最终就是
X
=
∑
1
n
(
a
i
t
i
M
i
)
(
m
o
d
L
c
m
)
X=\sum_{1}^{n}(a_{i}t_{i}M_{i}) (mod \quad Lcm)
X=∑1n(aitiMi)(modLcm)
[代码]
typedef long long LL;
void exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b){
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
return;
}
LL crt(LL Lcm,LL len) /*Lcm:最小公倍数;len:m[]数组长度*/
{
LL ans=0;
for(int i=1;i<=len;++i){
LL Mi=Lcm/m[i]; /*j从1~len,除i外,所有m[j]的乘积*/
LL ti,y;
exgcd(Mi,m[i],ti,y); /*ti为Mi在模m[i]意义下的乘法逆元*/
ans=((ans+a[i]*ti*Mi)%Lcm+Lcm)%Lcm; /*结论*/
}
return ans;
}
拓展中国剩余定理(excrt)
与中国剩余定理不同的是 不一定 两两互素
[结论]
通解
X
=
x
0
(
m
o
d
L
c
m
)
X=x_{0} (mod \quad Lcm)
X=x0(modLcm)
特解
x
0
=
a
1
+
t
1
m
1
x_{0}=a_{1}+t_{1}m_{1}
x0=a1+t1m1
[证明]
以下出现的字母均为整数
余
数
:
a
i
余数:a_{i}
余数:ai
模
数
:
m
i
模数:m_{i}
模数:mi
假
设
:
g
c
d
(
m
1
,
m
i
)
=
g
c
d
假设:gcd(m_{1},m_{i})=gcd
假设:gcd(m1,mi)=gcd
x
0
=
{
a
1
+
t
m
1
a
i
+
t
i
m
i
x_{0}=\left\{\begin{array}{cc} a_{1} +tm_{1}\\ a_{i} +t_{i}m_{i} \end{array}\right.
x0={a1+tm1ai+timi
移向可得:
t
m
1
+
(
−
t
i
)
m
i
=
a
i
−
a
1
tm_{1}+(-t_{i})m_{i}=a_{i}-a_{1}
tm1+(−ti)mi=ai−a1
根据不定方程(丢番图方程):
二元一次不定方程的一般形式为ax+by=c。其中 a,b,c 是整数,ab ≠ 0。此方程有整数解的充分必要条件是a、b的最大公约数整除c。设x,y是该方程的一组整数解,那么该方程的通解可表示为
x
=
x
0
+
b
g
c
d
(
a
,
b
)
t
;
y
=
y
0
−
b
g
c
d
(
a
,
b
)
t
;
x=x_{0}+\frac{b}{gcd(a,b)}t;y=y_{0}-\frac{b}{gcd(a,b)}t;
x=x0+gcd(a,b)bt;y=y0−gcd(a,b)bt;
所以对于
t
m
1
+
(
−
t
i
)
m
i
=
a
i
−
a
1
tm_{1}+(-t_{i})m_{i}=a_{i}-a_{1}
tm1+(−ti)mi=ai−a1
t
1
t_{1}
t1有解则有:
(
a
i
−
a
1
)
÷
g
c
d
=
0
(a_{i}-a_{1}) \div gcd=0
(ai−a1)÷gcd=0
则
t
=
t
0
+
m
i
g
c
d
k
t=t_{0}+\frac{mi}{gcd}k
t=t0+gcdmik
即
t
≡
t
0
(
m
o
d
m
i
g
c
d
)
t\equiv t_{0}(mod \quad \frac{mi}{gcd})
t≡t0(modgcdmi)
对
T
m
1
+
(
−
T
i
)
m
i
=
g
c
d
Tm_{1}+(-T_{i})m_{i}=gcd
Tm1+(−Ti)mi=gcd先用拓展欧几里得求
T
T
T
进而
t
=
T
a
i
−
a
1
g
c
d
(
m
o
d
m
[
i
]
g
c
d
)
t=T\frac{a_{i}-a_{1}}{gcd}(mod\quad \frac{m[i]}{gcd})
t=Tgcdai−a1(modgcdm[i])
则特解
x
0
=
a
1
+
t
m
1
x_{0}=a_{1}+tm_{1}
x0=a1+tm1
对于通解X与特解
x
0
x_{0}
x0满足:
{
X
=
a
1
+
k
1
m
1
x
0
=
a
1
+
k
2
m
1
\left\{\begin{array}{cc} X=a_{1} +k_{1}m_{1}\\ x_{0}=a_{1} +k_{2}m_{1} \end{array}\right.
{X=a1+k1m1x0=a1+k2m1
{
X
=
a
2
+
k
3
m
2
x
0
=
a
2
+
k
4
m
2
\left\{\begin{array}{cc} X=a_{2} +k_{3}m_{2}\\ x_{0}=a_{2} +k_{4}m_{2} \end{array}\right.
{X=a2+k3m2x0=a2+k4m2
上式减去下式得
X
−
x
0
=
(
k
1
−
k
2
)
m
1
=
(
k
3
−
k
4
)
m
2
X-x_{0}=(k_{1}-k_{2})m_{1}=(k_{3}-k_{4})m_{2}
X−x0=(k1−k2)m1=(k3−k4)m2
即
X
−
x
0
=
K
1
m
1
=
K
2
m
2
X-x_{0}=K_{1}m_{1}=K_{2}m_{2}
X−x0=K1m1=K2m2
假设
n
1
=
m
1
g
c
d
,
n
2
=
m
2
g
c
d
n_{1}=\frac{m_{1}}{gcd},n_2=\frac{m_{2}}{gcd}
n1=gcdm1,n2=gcdm2,显然
g
c
d
(
n
1
,
n
2
)
=
1
;
gcd(n_{1},n_{2})=1;
gcd(n1,n2)=1;
有
K
1
n
1
=
K
2
n
2
K_{1}n_{1}=K_{2}n_{2}
K1n1=K2n2
则
K
1
=
K
2
n
2
n
1
K_{1}=\frac{K_{2}n_{2}}{n_{1}}
K1=n1K2n2
而
g
c
d
(
n
1
,
n
2
)
=
1
,
K
1
为
整
数
gcd(n_{1},n_{2})=1,K_{1}为整数
gcd(n1,n2)=1,K1为整数
所以
K
2
%
n
1
=
0
K_{2} \% n_{1}=0
K2%n1=0
两边同乘
n
2
g
c
d
n_{2}gcd
n2gcd
K
2
n
2
g
c
d
%
n
1
n
2
g
c
d
=
0
K_{2}n_{2}gcd\% n_{1}n_{2}gcd =0
K2n2gcd%n1n2gcd=0
而
X
−
x
0
=
K
2
m
2
=
K
2
n
2
g
c
d
X-x_{0} =K_{2}m_{2}=K_{2}n_{2}gcd
X−x0=K2m2=K2n2gcd
n
1
n
2
g
c
d
=
n
1
g
c
d
n
2
g
c
d
g
c
d
=
L
c
m
(
m
1
,
m
2
)
=
L
c
m
n_{1}n_{2}gcd=\frac{n_{1}gcd n_{2}gcd}{gcd}=Lcm(m_{1},m_{2})=Lcm
n1n2gcd=gcdn1gcdn2gcd=Lcm(m1,m2)=Lcm
所以
(
X
−
x
0
)
%
L
c
m
=
0
(X-x_{0}) \% Lcm=0
(X−x0)%Lcm=0
即通解
X
≡
x
0
(
m
o
d
L
c
m
)
X\equiv x_{0}(mod \quad Lcm)
X≡x0(modLcm)
[代码]
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=1e5+9;
LL a[N],m[N];
LL ksc(LL x,LL y,LL mod)
{
return (x*y-(LL)((long double)x*y/mod)*mod+mod)%mod;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b){
x=1;
y=0;
return a;
}
LL gcd=exgcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
}
LL excrt(LL len)
{
LL x=a[1],Lcm=m[1],t,y; /*一个方程时,x=a[1],Lcm=m[1]*/
for(int i=2;i<=len;++i){
a[i]-=x; /*求a[i]-a[1]*/
LL gcd=exgcd(Lcm,m[i],t,y); /*求gcd与证明过程中的T*/
if(a[i]%gcd)return -1; /*方程无解*/
t=ksc(t,a[i]/gcd,m[i]/gcd); /*O(1)快速乘求t*/
x+=t*Lcm; /*求特解x0*/
Lcm*=m[i]/gcd; /*更新Lcm*/
x=(x%Lcm+Lcm)%Lcm; /*更新通解*/
}
return x;
}
int main()
{
ios::sync_with_stdio(false);
LL n;
while(cin>>n){
memset(a,0,sizeof(a));
memset(m,0,sizeof(m));
for(int i=1;i<=n;++i)cin>>m[i]>>a[i];
cout<<excrt(n)<<endl;
}
return 0;
}