中国剩余定理
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; }
以上是关于中国剩余定理的主要内容,如果未能解决你的问题,请参考以下文章