中国剩余定理(CRT)笔记

给定 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} xxxa1(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 xi=1naitiMi(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, tiMi1(modmi), Mj0(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} xxxxj=1najtjMj(modmi)aitiMi+j=1,i=jnajtjMj(modmi)ai1+j=1,i=jn0(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} x1x20(modmi)

x 1 ≡ a i ( m o d m i ) x_1\equiv a_i\pmod {m_i} x1ai(modmi)
x 2 ≡ a i ( m o d m i ) x_2\equiv a_i\pmod {m_i} x2ai(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} x1x2aiai(modmi)
x 1 − x 2 ≡ 0 ( m o d m i ) x_1-x_2\equiv0\pmod {m_i} x1x20(modmi)

那么也就是 m i ∣ ( x 1 − x 2 ) m_i\mid(x_1-x_2) mi(x1x2) 由此可以推出 M ∣ ( x 1 − x 2 ) M\mid(x_1-x_2) M(x1x2)

也就是两个解的差最少相差 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 是唯一解 M0(modmi)对于x,x+kMxai(modmi)x+kM也是一个解x是唯一解

例题

P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪 模板题

P3868 [TJOI2009] 猜数字

可以写成同余方程组:

{ 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} na1(modb1)na2(modb2)    nak(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 中数学证明可以不严谨。

  • 41
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值