给定
n
n
n 个同余方程:
{
x
≡
a
1
(
m
o
d
m
1
)
x
≡
a
2
(
m
o
d
m
2
)
⋮
x
≡
a
k
(
m
o
d
m
k
)
\begin{cases}x&\equiv a_1\pmod {m_1}\\x&\equiv a_2\pmod {m_2}\\&\vdots\\x&\equiv a_k\pmod {m_k}\end{cases}
⎩
⎨
⎧xxx≡a1(modm1)≡a2(modm2)⋮≡ak(modmk)
其中保证 m 1 , m 2 , . . . , m k m_1,m_2,...,m_k m1,m2,...,mk 两两互质,求 x x x 的通解。
中国剩余定理也称作 CRT ,我们以以下方式构造:
记
M
=
∏
m
i
,
M
i
=
M
m
i
M=\prod m_i,M_i=\frac{M}{m_i}
M=∏mi,Mi=miM,
t
i
t_i
ti 是
M
i
M_i
Mi 在模
m
i
m_i
mi 的逆元。
那么 x x x 的通解为 x ≡ ∏ i = 1 n a i t i M i ( m o d M ) x\equiv\prod\limits_{i=1}^n a_it_iM_i\pmod M x≡i=1∏naitiMi(modM)
证明:
我们可以知道 i ≠ j , t i ⋅ M i ≡ 1 ( m o d m i ) , M j ≡ 0 ( m o d m i ) i\not=j,~t_i\cdot M_i\equiv1\pmod {m_i},~M_j\equiv0\pmod{m_i} i=j, ti⋅Mi≡1(modmi), Mj≡0(modmi) 我们再带入进去为:
x ≡ ∏ j = 1 n a j t j M j ( m o d m i ) x ≡ a i t i M i + ∏ j = 1 , i ≠ j n a j t j M j ( m o d m i ) x ≡ a i ⋅ 1 + ∏ j = 1 , i ≠ j n 0 ( m o d m i ) x ≡ a i ( m o d m i ) \begin{aligned}x&\equiv\prod\limits_{j=1}^n a_jt_jM_j\pmod {m_i}\\x&\equiv a_it_iM_i+\prod\limits_{j=1,i\not=j}^n a_jt_jM_j\pmod {m_i}\\x&\equiv a_i\cdot1+\prod\limits_{j=1,i\not=j}^n0\pmod {m_i}\\x&\equiv a_i\pmod {m_i}\end{aligned} xxxx≡j=1∏najtjMj(modmi)≡aitiMi+j=1,i=j∏najtjMj(modmi)≡ai⋅1+j=1,i=j∏n0(modmi)≡ai(modmi)
可以发现等式成立。
接着证明存在唯一解:
先假设 x 1 , x 2 x_1,x_2 x1,x2 是同余方程组的解,那么肯定有 x 1 − x 2 ≡ 0 ( m o d m i ) x_1-x_2\equiv0\pmod {m_i} x1−x2≡0(modmi)
x
1
≡
a
i
(
m
o
d
m
i
)
x_1\equiv a_i\pmod {m_i}
x1≡ai(modmi)
x
2
≡
a
i
(
m
o
d
m
i
)
x_2\equiv a_i\pmod {m_i}
x2≡ai(modmi)
x
1
−
x
2
≡
a
i
−
a
i
(
m
o
d
m
i
)
x_1-x_2\equiv a_i-a_i\pmod {m_i}
x1−x2≡ai−ai(modmi)
x
1
−
x
2
≡
0
(
m
o
d
m
i
)
x_1-x_2\equiv0\pmod {m_i}
x1−x2≡0(modmi)
那么也就是 m i ∣ ( x 1 − x 2 ) m_i\mid(x_1-x_2) mi∣(x1−x2) 由此可以推出 M ∣ ( x 1 − x 2 ) M\mid(x_1-x_2) M∣(x1−x2)
也就是两个解的差最少相差 M M M。
∵ M ≡ 0 ( m o d m i ) ∴ 对于 ∀ x , x + k M ≡ x ≡ a i ( m o d m i ) ∵ x + k M 也是一个解 ∴ x 是唯一解 \because M\equiv0\pmod {m_i}\\\therefore 对于\forall x,x+kM\equiv x\equiv a_i\pmod {m_i}\\\because x+kM 也是一个解\\\therefore x 是唯一解 ∵M≡0(modmi)∴对于∀x,x+kM≡x≡ai(modmi)∵x+kM也是一个解∴x是唯一解
例题
P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪 模板题
可以写成同余方程组:
{ n ≡ a 1 ( m o d b 1 ) n ≡ a 2 ( m o d b 2 ) ⋮ n ≡ a k ( m o d b k ) \begin{cases}n\equiv a_1\pmod{b_1}\\n\equiv a_2\pmod{b_2}\\~~~~\vdots\\n\equiv a_k\pmod{b_k}\end{cases} ⎩ ⎨ ⎧n≡a1(modb1)n≡a2(modb2) ⋮n≡ak(modbk)
直接 CRT 就行
#include<bits/stdc++.h>
#define all(x) x.begin(),x.end()
#define ll long long
#define ull unsigned long long
#define db double
#define x first
#define y second
#define fast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define endl '\n'
#define pb push_back
#define swap(a,b) a=a^b,b=a^b,a=a^b
#define mem(x,a) memset(x,a,sizeof(x))
#define rep(l,r,i) for(int i=l,END##i=r;i<=END##i;i++)
#define per(r,l,i) for(int i=r,END##i=l;i>=END##i;i--)
#define sc scanf
#define pr printf
#define pii pair<int,int>
#define pll pair<ll,ll>
const int INF=0x3f3f3f3f;
#define vi vector<int>
namespace fast_io{
char buf[1<<12],*p1=buf,*p2=buf,sr[1<<23],z[23],nc;int C=-1,Z=0,Bi=0;
inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;}
inline ll read(){
ll x=0,y=1;while(nc=gc(),(nc<'0'||nc>'9')&&nc!=-1)if(nc=='-')y=-1;
Bi=1,x=nc^'0';while(nc=gc(),'0'<=nc&&nc<='9')x=(x<<1)+(x<<3)+(nc^'0'),Bi++;
return x*y;
}
inline db gf(){int a=read(),b=(nc!='.')?0:read();return(b?a+(db)b/pow(10,Bi):a);}
inline int gs(char*s) {char c,*t =s;while(c=gc(),c<32);*s++=c;while(c=gc(),c>32)*s++=c;return s-t;}
inline void ot(){fwrite(sr,1,C+1,stdout);C=-1;}
inline void flush(){if(C>1<<22)ot();}
template<typename T>
inline void write(T x,char t){
int y=0;if(x<0)x=-x,y=1;
while(z[++Z]=x%10+'0',x/=10);if(y)z[++Z]='-';
while(sr[++C]=z[Z],--Z);sr[++C]=t;flush();
}
inline void write(char*s){int l=strlen(s);for(int i=0;i<l;i++)sr[++C]=*s++;flush();}
};
using namespace std;
const int MAXN=20;
int a[MAXN],b[MAXN],n;
ll M=1,m[MAXN],ans;
void exgcd(ll a,ll b,ll &x,ll &y){
if(!b)x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
ll qm(ll a,ll b,ll p){
ll res=0;
for(;b;a=(a+a)%p,b>>=1)if(b&1)res=(res+a)%p;
return res;
}
int main(){
// cout<<qm(10,10,114514)<<"\n";
cin>>n;
rep(1,n,i)cin>>a[i];
rep(1,n,i)cin>>b[i],M*=b[i];
rep(1,n,i){
m[i]=M/b[i];
ll t,y;
exgcd(m[i],b[i],t,y);
ans=(ans+qm(a[i]*t,m[i],M))%M;
}
cout<<(ans%M+M)%M<<"\n";
// cout<<"Y";
return 0;
}
此文章为本人的笔记,欢迎各位大佬来纠正错误,当然在 OI 中数学证明可以不严谨。