中国剩余定理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中国剩余定理相关的知识,希望对你有一定的参考价值。

互质

对于互质的$m_1,m_2,m_3....m_n$,如果有$x \equiv a_i \pmod{m_i} $,设$M=\prod m_i$,那么$x$在$M$下的解为$\sum a_iM_iM_i^{-1}$

其中$M_i=\frac{M}{a_i}$,$M_i^{-1}$为$M_i$在$m_i$意义下的乘法逆元

模板题

//POJ 1006
//by Cydiater
//2017.2.18
#include <iostream>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <cstring>
#include <string>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <bitset>
#include <set>
#include <vector>
#include <complex>
using namespace std;
#define ll long long
#define up(i,j,n)	for(ll i=j;i<=n;i++)
#define down(i,j,n)	for(ll i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
inline ll read(){
	char ch=getchar();ll x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
ll a[5],m[5],s,Case;
namespace solution{
	void exgcd(ll a,ll b,ll &x,ll &y){
		if(b==0){x=1;y=0;return;}
		exgcd(b,a%b,x,y);
		ll t=x;x=y;y=t-a/b*y;
	}
	ll Inv(ll a,ll b){
		ll x,y;
		exgcd(a,b,x,y);
		x=((x+b)%b+b)%b;
		return x;
	}
	ll crt(ll *a,ll *m,ll N){
		ll M=1,ans=0;
		up(i,1,N)M*=m[i];
		up(i,1,N){
			ll Mi=M/m[i],inv=Inv(Mi,m[i]);
			(ans+=a[i]*Mi*inv)%=M;
		}
		(ans+=M)%=M;
		return ans;
	}
	void Solve(){
		m[1]=23;m[2]=28;m[3]=33;
		up(i,1,3)a[i]=read();s=read();
		if(a[1]==-1)exit(0);
		up(i,1,3)a[i]%=m[i];
		ll x=crt(a,m,3);
		while(x<=s)x+=m[1]*m[2]*m[3];
		printf("Case %lld: the next triple peak occurs in %lld days.\n",++Case,x-s);
	}
}
int main(){
	freopen("input.in","r",stdin);
	using namespace solution;
	while(true)Solve();
	return 0;
}

 非互质

利用exgcd合并方程。

在有$x \equiv  a1_ \pmod{m_1} $和$x\equiv a_2 \pmod{m_2}$的前提下。

可以考虑把方程联立:$a_2-a_1 = k_1m_1+k_2m_2$

用exgcd解出后可以将两方程合并,不断合并后即为最终结果

模板题

//POJ2891
//by Cydiater
//2017.2.18
#include <iostream>
#include <queue>
#include <map>
#include <ctime>
#include <cmath>
#include <cstring>
#include <string>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <bitset>
#include <set>
#include <vector>
#include <complex>
using namespace std;
#define ll long long
#define up(i,j,n)	for(ll i=j;i<=n;i++)
#define down(i,j,n)	for(ll i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
const ll MAXN=1005;
const ll oo=1LL<<50;
inline ll read(){
	char ch=getchar();ll x=0,f=1;
	while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
ll a[MAXN],m[MAXN],N;
namespace solution{
	ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
	void exgcd(ll a,ll b,ll &x,ll &y){
		if(!b){x=1;y=0;return;}
		exgcd(b,a%b,x,y);
		ll t=x;x=y;y=t-a/b*y;
	}
	ll Inv(ll a,ll b){
		ll x,y;
		exgcd(a,b,x,y);
		return ((x+b)%b+b)%b;
	}
	bool Merge(ll a1,ll m1,ll a2,ll m2,ll &a3,ll &m3){
		ll d=gcd(m1,m2),c=a2-a1;
		if(c%d)return 0;
		m1/=d;m2/=d;c/=d;
		//c=(c%m2+m2)%m2;
		c*=Inv(m1,m2);
		c%=m2;
		a3=a1+c*m1*d;
		m3=m1*m2*d;
		a3=((a3%m3+m3)%m3+m3)%m3;
		return 1;
	}
	ll CRT(ll N,ll *a,ll *m){
		ll a1=a[1],m1=m[1];
		up(i,2,N){
			ll a2=a[i],m2=m[i],a3,m3;
			if(!Merge(a1,m1,a2,m2,a3,m3))return -1;
			a1=a3;m1=m3;
		}
		return (a1%m1+m1)%m1;
	}
	void Solve(){
		up(i,1,N){
			m[i]=read();a[i]=read();
			a[i]%=m[i];
		}
		printf("%I64d\n",CRT(N,a,m));
	}
}
int main(){
	freopen("input.in","r",stdin);
	using namespace solution;
	while(scanf("%I64d",&N)!=EOF)Solve();
	return 0;
}

 

以上是关于中国剩余定理的主要内容,如果未能解决你的问题,请参考以下文章

中国剩余定理

简述中国剩余定理

中国剩余定理过程

什么叫中国剩余定理

中国剩余定理与扩展中国剩余定理

中国剩余定理公式是啥?