更新ing
中国剩余定理
用于求解一元线性同余方程组
{
x
%
m
1
=
a
1
x
%
m
2
=
a
2
x
%
m
3
=
a
3
⋮
x
%
m
k
=
a
k
\begin{cases} x\%m_{1}=a_{1}\\ x\%m_{2}=a_{2}\\ x\%m_{3}=a_{3}\\ \vdots\\ x\%m_{k}=a_{k} \end{cases}
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧x%m1=a1x%m2=a2x%m3=a3⋮x%mk=ak
其中 m i m_i mi两两互质
--------------------------------我是来自百度百科的分界线-----------------------------------
孙子定理是中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。又称中国余数定理。一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作《孙子算经》卷下第二十六题,叫做“物不知数”问题,原文如下:
有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?即,一个整数除以三余二,除以五余三,除以七余二,求这个整数。《孙子算经》中首次提到了同余方程组问题,以及以上具体问题的解法,因此在中文数学文献中也会将中国剩余定理称为孙子定理。
中国剩余定理说明:假设整数
m
1
,
m
2
,
⋯
,
m
n
m_{1},m_{2}, \cdots ,m_{n}
m1,m2,⋯,mn两两互质,则对任意的整数:
a
1
,
a
2
,
⋯
,
a
n
a_{1},a_{2},\cdots ,a_{n}
a1,a2,⋯,an,方程组有解,并且通解可以用如下方式构造得到:
设
M
M
M是整数
m
1
,
m
2
,
⋯
,
m
n
m_{1},m_{2}, \cdots ,m_{n}
m1,m2,⋯,mn的乘积,并设
M
i
=
M
m
i
,
i
∈
(
1
,
2
,
3
,
⋯
,
n
)
M_{i}=\frac{M}{m_{i}},i\in{(1,2,3,\cdots,n)}
Mi=miM,i∈(1,2,3,⋯,n)是除了
m
i
m_{i}
mi以外的n- 1个整数的乘积。
设
t
i
=
M
i
−
1
t_{i}=M_{i}^{-1}
ti=Mi−1为
M
i
M_{i}
Mi模
m
i
m_{i}
mi的数论倒数(
t
i
t_{i}
ti为
M
i
M_{i}
Mi模
m
i
m_{i}
mi意义下的逆元)
方程组的通解形式为
x
=
a
1
t
1
M
1
+
a
2
t
2
M
2
+
⋯
+
a
n
t
n
M
n
=
Σ
i
−
1
n
a
i
t
i
M
i
x=a_{1}t_{1}M_{1}+a_{2}t_{2}M_{2}+\cdots+a_{n}t_{n}M_{n}=\Sigma_{i-1}^{n}a_{i}t_iM_i
x=a1t1M1+a2t2M2+⋯+antnMn=Σi−1naitiMi
在模
M
M
M的意义下,方程组只有一个解:
x
=
⟮
Σ
i
−
1
n
a
i
t
i
M
i
⟯
%
M
x=\lgroup \Sigma_{i-1}^{n}a_{i}t_iM_i \rgroup \%M
x=⟮Σi−1naitiMi⟯%M
代码
int k;
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b){
d = a;x = 1;y = 0;return;
}
ex_gcd(b,a%b,d,y,x);
y -= x*(a/b);
}
ll inv(ll a,ll p){
ll d,x,y;
ex_gcd(a,p,d,x,y);
return d == 1 ? (x%p+p)%p : -1;
}
ll crt(int n,ll *a,ll *m){ // x%m[i]=a[i]
ll M = 1,ret = 0;
for(int i = 1; i <= n; ++i) M *= m[i];
for(int i = 1; i <= n; ++i){
ll Mi = M / m[i];
ret = (ret + Mi*inv(Mi,m[i])*a[i])%M;
}
return (ret+M)%M;
}
ll m[maxn],a[maxn];
int main(){
int n;
cin>>n;
for(int i = 1; i <= n; ++i){
scanf("%lld%lld",&m[i],&a[i]);
}
ll ans = crt(n,a,m);
printf("%lld\n",ans);
return 0;
}
拓展中国剩余定理
将中国剩余定理拓展到
m
i
m_{i}
mi不互质的情况
代码
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y){
if(!b){
d = a;x = 1;y = 0;return;
}
ex_gcd(b,a%b,d,y,x);
y -= x*(a/b);
}
ll ex_crt(int n,ll *a,ll *m){ // x%m[i]=a[i]
ll d,M = m[1],A = a[1],x,y;
for(int i = 2; i <= n; ++i){
ex_gcd(M,m[i],d,x,y);
ll c = a[i]-A;
if(c%d) return -1;
ll mul = m[i]/d;
x = (c/d*x%mul+mul)%mul;
A = A+M*x;
M = M*mul;
A %= M;
}
return (A+M)%M;
}
ll m[maxn],a[maxn];
int main(){
int n;
cin>>n;
for(int i = 1; i <= n; ++i){
scanf("%lld%lld",&m[i],&a[i]);
}
ll ans = ex_crt(n,a,m);
printf("%lld\n",ans);
return 0;
}