中国剩余定理(CRT)
“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物几何?” ——《孙子算经》
定理内容
一次同余方程组 :
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) ⋯ x ≡ a n ( m o d m n ) \left\{ \begin{array}{lcl} x≡a_{1} (mod\space m_{1})\\ x≡a_{2} (mod\space m_{2}) \\ \cdots \\ x≡a_{n} (mod\space m_{n}) \end{array} \right. ⎩ ⎨ ⎧x≡a1(mod m1)x≡a2(mod m2)⋯x≡an(mod mn)
如果满足 m i m_{i} mi 两两互质,则在 m o d M ( M = m 1 ⋅ m 2 ⋅ m 3 ⋯ m n ) mod\space M(M=m_{1}\cdot m_{2}\cdot m_{3}\cdots m_{n}) mod M(M=m1⋅m2⋅m3⋯mn) 意义下,存在唯一解.
定理证明
构造解 M = m 1 ⋅ m 2 ⋅ m 3 ⋯ m n M=m_{1}\cdot m_{2}\cdot m_{3}\cdots m_{n} M=m1⋅m2⋅m3⋯mn , M i = M / m i M_{i}=M/m_{i} Mi=M/mi, t i t_{i} ti 为 M i M_{i} Mi 在 m o d m i mod\space m_{i} mod mi 意义下的乘法逆元, g c d ( M i , m i ) = 1 gcd(M_{i},m_{i})=1 gcd(Mi,mi)=1 .
则 x = ( ∑ i = 1 n a i t i M i ) x=(\sum\limits_{i=1}^na_{i}t_{i}M_{i}) x=(i=1∑naitiMi) ( m o d M ) (mod\space M) (mod M)
带入验证,对于每一个一次同于方程 x ≡ a j ( m o d m j ) x≡a_{j} (mod\space m_{j}) x≡aj(mod mj) .
当 i ≠ j i≠j i=j 时,一定有 m j ∣ a i t i M i m_{j}\space |\space a_{i}t_{i}M_{i} mj ∣ aitiMi , a i t i M i m o d m j = 0 a_{i}t_{i}M_{i}\space mod\space m_{j}=0 aitiMi mod mj=0 .
当 i = j i=j i=j 时,一定有 a i t i M i = a j a_{i}t_{i}M_{i}=a_{j} aitiMi=aj , a i t i M i m o d m j = a j a_{i}t_{i}M_{i}\space mod\space m_{j}=a_{j} aitiMi mod mj=aj .
由此,同余方程组成立 .
典型例题
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=15;
namespace zyx_{
ll read(){
ll x=0;int f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
void print(ll x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar('0'+x%10);
return ;
}
ll mul(ll a,ll b,ll mod){
ll res=0;
a%=mod;
while(b){
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=1,y=0;
return a;
}
ll d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
ll inv(ll a,ll b){
ll x,y;
exgcd(a,b,x,y);
return (x%b+b)%b;
}
ll n,M=1,ans,a[N],b[N];
int my_main(){
n=read();
for(int i=1;i<=n;i++)
a[i]=read(),b[i]=read(),M*=a[i];
for(int i=1;i<=n;i++){
ll Mi=M/a[i];
ll tmp=mul(b[i],Mi,M);
tmp=mul(tmp,inv(Mi,a[i]),M);
ans=(ans+tmp)%M;
}
print(ans);
return 0;
}
}
int main(){
zyx_::my_main();
return 0;
}
扩展中国剩余定理(EXCRT)
中国剩余定理的局限性
中国剩余定理(CRT)不能解决模数不互质情况的模线性同余方程组:
a n s ≡ ∑ i = 1 n a i ⋅ M i ⋅ i n v ( M i , m i ) ( m o d M ) ans≡ \sum\limits_{i=1}^na_{i}\cdot M_{i}\cdot inv(M_{i},m_{i})\space (mod\space M) ans≡i=1∑nai⋅Mi⋅inv(Mi,mi) (mod M)
其中的 i n v ( M i , m i ) inv(M_{i},m_{i}) inv(Mi,mi) 在 M i , m i M_{i},m_{i} Mi,mi 不互质的情况下,根本不存在。而只要有任意两个模数不互质,就会破坏掉整个解。
解决方案
扩展中国剩余定理的核心思想就是将两个同余方程组两两合并:
对于两个同余方程:
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) \left\{ \begin{array}{lcl} x≡a_{1} (mod\space m_{1})\\ x≡a_{2} (mod\space m_{2}) \end{array} \right. {x≡a1(mod m1)x≡a2(mod m2)
可以将其转化为不定方程组:
{ x = k 1 m 1 + a 1 x = k 2 m 2 + a 2 \left\{ \begin{array}{lcl} x=k_{1}m_{1}+a_{1}\\ x=k_{2}m_{2}+a_{2} \end{array} \right. {x=k1m1+a1x=k2m2+a2
合并,移项后,得到新的不定方程:
k 1 m 1 − k 2 m 2 = a 2 − a 1 k_{1}m_{1}-k_{2}m_{2}=a_{2}-a_{1} k1m1−k2m2=a2−a1
由裴蜀定理得,当且仅当 g c d ( m 1 , m 2 ) ∣ ( a 2 − a 1 ) gcd(m_{1},m_{2})\space |\space (a_{2}-a_{1}) gcd(m1,m2) ∣ (a2−a1) 时,有解;
我们就能够根据扩展欧几里德算法计算出系数:
设 d = g c d ( m 1 , m 2 ) d=gcd(m_{1},m_{2}) d=gcd(m1,m2)
将方程左右两边同时除以 d d d ,得
m 1 d k 1 + m 2 d ( − k 2 ) = a 2 − a 1 d \frac{m_{1}}{d}k_{1}+\frac{m_{2}}{d}(-k_{2})=\frac{a_{2}-a_{1}}{d} dm1k1+dm2(−k2)=da2−a1
为了简化方程,令:
m 1 ′ = m 1 d k 1 , m 2 ′ = m 2 d k 1 , c = a 2 − a 1 d m_{1}^{'}=\frac{m_{1}}{d}k_{1},m_{2}^{'}=\frac{m_{2}}{d}k_{1},c=\frac{a_{2}-a_{1}}{d} m1′=dm1k1,m2′=dm2k1,c=da2−a1
方程变为:
m 1 ′ k 1 + m 2 ′ ( − k 2 ) = c m_{1}^{'}k_{1}+m_{2}^{'}(-k_{2})=c m1′k1+m2′(−k2)=c
其中 g c d ( m 1 ′ , m 2 ′ ) = 1 gcd(m_{1}^{'},m_{2}^{'})=1 gcd(m1′,m2′)=1 ,根据裴蜀定理,一定有:
m 1 ′ u + m 2 ′ v = 1 m_{1}^{'}u+m_{2}^{'}v=1 m1′u+m2′v=1
则通解:
k 1 = c u + t m 2 ′ , k 2 = − ( c v − t m 1 ′ ) ( t ∈ Z ) k_{1}=cu+tm_{2}^{'},k2=-(cv-tm_{1}^{'})\space (t\in Z) k1=cu+tm2′,k2=−(cv−tm1′) (t∈Z)
代回求 x x x :
x = a 1 + k 1 m 1 = a 1 + ( c u + t m 2 ′ ) m 1 x=a_{1}+k_{1}m_{1}=a_{1}+(cu+tm_{2}^{'})m_{1} x=a1+k1m1=a1+(cu+tm2′)m1
化简,得:
x = a 1 + c u ⋅ m 1 + t ⋅ m 1 m 2 d x=a_{1}+cu\cdot m_{1}+t\cdot \frac{m_{1}m_{2}}{d} x=a1+cu⋅m1+t⋅dm1m2
令 x 0 = a 1 + c u ⋅ m 1 x_{0}=a_{1}+cu\cdot m_{1} x0=a1+cu⋅m1 ,则合并结果为:
x ≡ x 0 ( m o d l c m ( m 1 , m 2 ) ) x≡x_{0}\space (mod\space lcm(m_{1},m_{2})) x≡x0 (mod lcm(m1,m2))
典型例题
#include<bits/stdc++.h>
using namespace std;
typedef __int128 ll;
const int N=1e5+5;
namespace zyx_{
ll read(){
ll x=0;int f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
void print(ll x){
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
return ;
}
ll n,A=1,B=0,x,y;
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){
x=1,y=0;
return a;
}else{
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
}
int my_main(){
n=read();
for(int i=1;i<=n;i++){
ll a,b;
a=read(),b=read();
ll d=exgcd(A,a,x,y);
x=(B-b)/d*x;
B=B-A*x;
A=a/d*A;
B=(B%A+A)%A;
}
ll ans=(B%A+A)%A;
print(ans);
return 0;
}
}
int main(){
zyx_::my_main();
return 0;
}
956

被折叠的 条评论
为什么被折叠?



