中国剩余定理CRT&扩展中国剩余定理EXCRT

中国剩余定理

解法

[left{egin{matrix} \x equiv b_{1}(mod a_{1}) \x equiv b_{2}(mod a_{2}) \... \x equiv b_{n}(mod a_{n}) end{matrix} ight. ]

其中(a_{i})互质,求(x)
结论:在(lcm(prod a_{i}))的剩余系下,有唯一解:

[sum a_{i} imes M_{i} imes M^{-1}_{i} ]

其中,(M_{i}=prod_{j e i }^{} a_{j}),(M_{i}^{-1})(M_{i})((mod a_{i}))下的逆元
不想证了证明先咕了吧

例题

P1495中国剩余定理/曹冲养猪

#include<bits/stdc++.h>
#define ll long long 
#define maxn 15
using namespace std;

ll n,a[maxn],b[maxn];
ll m=1,ans=0;

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=y-(a/b)*x;
	return d;
}

signed int main(){
	cin>>n;
	for(ll i=1;i<=n;i++) {
		cin>>a[i]>>b[i];
		m*=a[i];
	}
	for(ll i=1;i<=n;i++){
		ll x=0,y=0;
		exgcd(m/a[i],a[i],x,y);
		ans=((ans+(m/a[i])*b[i]*x)%m+m)%m;
	}
	cout<<ans%m<<endl;
	return 0;
}

扩展中国剩余定理

解法

用于处理模数不互质的情况
思路是两两合并,最后转化为求(k)次扩展欧几里得,得到式子:

[x=X+k imes lcm(a1+a2) ]

即为

[x equiv X mod(lcm(a_{1},a_{2}) ]

至于过程中的合并什么的,就是先用EXGCD把两个方程合并成一个方程放进方程组里:

[x equiv b_{1}(mod a_{1}),x equiv b_{2}(mod a_{2}) ]

得到:

[x=k_{1}a_{1}+b_{1}=k_{2}a_{2}+b_{2} ]

移项:

[k_{1}a_{1}+k_{2}a_{2}=b_{2}-b_{1} ]

解出:

[k_{1}a_{1}+k_{2}a_{2} equiv gcd(a_{1},a_{2}) ]

有解条件为(gcd(a_{1},a_{2})|b_{2}-b_{1})
然后一直这样合并合并,直到只剩下一个方程,哦如果合并的过程中无解了那就返回-1(虽然这道题的数据保证有解)

例题

P4777扩展中国剩余定理

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define maxn 100010
#define ll long long
using namespace std;
template<typename T>
inline void read(T &x){
	x=0; bool flag=0; char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
	for(;isdigit(c);c=getchar()) x=x*10+(c^48);
	if(flag) x=-x;
}

ll n,a[maxn],b[maxn];

ll qmul(ll a,ll b,ll p){
	ll res=0;
	for(;b;b>>=1,a=(a+a)%p) if(b&1) res=(res+a)%p;
	return res%p;
}

ll exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1;y=0;
		return a;
	}
	ll d=exgcd(b,a%b,y,x);
	y=y-(a/b)*x;
	return d;
}

ll excrt(ll n,ll *a,ll *b){
	ll x,y,k,tmp;
	ll ans=a[1],m=b[1];
	for(int i=2;i<=n;i++){
		k=exgcd(m,b[i],x,y);
		tmp=((a[i]-ans)%b[i]+b[i])%b[i];
		if(tmp%k!=0) return -1; //判断是否无解 
		ans+=qmul(x,tmp/k,b[i])*m;
		m*=b[i]/k;
		ans=(ans%m+m)%m; 
	}
	return ans;
}

int main(){
	read(n);
	for(int i=1;i<=n;i++)
		read(b[i]),read(a[i]);//注意把读入反过来了(要不调了半天找不出来错...... 
	cout<<excrt(n,a,b);
	return 0;
} 
原文地址:https://www.cnblogs.com/DReamLion/p/14507042.html