数论 中国剩余定理
中国剩余定理(Chinese Remainder Theorem)
定义
又名孙子定理,最早出现在《孙子算经》中
对于下面的一元线性同余方程组:
中国剩余定理给出了其有解的判定条件及解集
判定条件: \(m_1,m_2,\dots,m_n\) 两两互质
通解:
-
设 \(M=\prod\limits_{i=1}^nm_i,M_i=\frac M{m_i}\)
-
设 \(t_i\) 为 \(M_i\) 模 \(m_i\) 的逆元
-
方程组通解的形式就为:
\[\begin{align} \notag x&=a_1t_1M_1+a_2t_2M_2+\dots+a_nt_nM_n\pmod M\\\notag &=\sum_{i=1}^na_it_iM_i\pmod M \end{align} \]
证明
证明: \(x=\sum\limits_{i=1}^na_it_iM_i\) 是方程组的一个解
证明: \(x=kM+\sum\limits_{i=1}^na_it_iM_i\) 是方程组的通解
用法
\(O(n\log n)\)
typedef long long lld;
const int maxn=10+12;
lld a[maxn],m[maxn],M=1;
int n;
//exGcd
lld gcd(lld a,lld b,lld&x,lld&y){
if(b==0){
x=1;y=0;return a;
}
lld g=gcd(b,a%b,y,x);
y=y-a/b*x;
return g;
}
lld crt(lld a[],lld m[]){
lld ans=0,t,y;//t refers to M/m[i]'s Inverse Element
for(int i=1;i<=n;i++){
gcd(M/m[i],m[i],t,y);//M refers to \prod_{i=1}^n(m[i])
//M should be preprocessed
//use exGcd to get Inverse Element
//now t is M/m[i]'s Inserse Element
ans=(ans+(M/m[i]*t*a[i])%M+M)%M;//According to the formula
//Explian: why wo should use "(M/m[i]*t*a[i])%M+M"
//that is to avoid negative numbers
//we know that (x+M) is still the solution of the system of equations
//when x is a negative number
//x%M is a negative number between (-M,0)
//so x%M+M is a positive number between (0,M)
//in this way we could make sure that the answer is what we need
}
return ans;
}
ex-CRT
定义
扩展中国剩余定理,是对中国剩余定理的一个补充,用于解决中国剩余定理中模数 \(m_i\) 不互质的情况。
中国剩余定理的限制
中国剩余定理对下面的这个方程组 \(S\)
给出的通解形式为:
其中 \(M=\prod\limits_{i=1}^nm_i,M_I=\frac M{m_i},M_it_i\equiv1\pmod {m_i}\)
不难发现当 \(M_i和m_i\) 不互质时, \(t_i\) 根本无法求得
所以这时需要扩展中国剩余定理 exCRT 出场了
(下文中均使用exCRT代指扩展中国剩余定理)
exCRT的基本思想
不同于中国剩余定理,exCRT尝试不停将两个方程合并为一个,这样直到方程只剩一个时,问题也就迎刃而解了
如何合并呢?
为什么通解间一定间隔 \(\text{lcm}(m_1,m_2)\) ?
设上述方程组的解集中存在两个数 \(\text{lcm}(m_1,m_2)\ge x\ge y\ge 0\in\N\)
有:
因为 \(x,y\le \text{lcm}(m_1,m_2)\Rightarrow x-y\le\text{lcm}(m_1,m_2)\)
所以 \(x-y=0\Rightarrow x=y\)
得证
实现
typedef long long lld;
lld n,m[maxn],a[maxn];
inline lld times(lld a,lld b,lld mo){
lld ans=0;
while(b){
if(b&1)an=(an+a)%mo;
a=(a+a)%mo;
b>>=1;
}
return an%mo;
}
inline lld gcd(lld a,lld b,lld &x,lld &y){
if(b==0){
x=1;y=0;return a;
}
lld g=gcd(b,a%b,y,x);
y=y-a/b*x;
return g;
}
inline void sol(){
lld ans=a[1],M=m[1],x,y;
for(int i=2;i<=n;i++){
lld res=((a[i]-ans)%m[i]+m[i])%m[i];
lld g=gcd(M,m[i],x,y);
if(res%g!=0){
printf("%d",-1);
return;
}
x=times(x,res/g,m[i]);
ans+=x*M;
M=m[i]/g*M;
ans=(ans%M+M)%M;
}
printf("%lld",ans);
}

浙公网安备 33010602011771号