中国剩余定理与扩展中国剩余定理
概述
中国剩余定理是同余中常用的辅助手段,常用来合并多个同余方程的解(如MTT)。其技术难度不高,代码也很短,可以在NOIP中出现。
中国剩余定理CRT
形式
给定 \(n\) 组非负整数 \(m_i, a_i\) ,求解关于 \(x\) 的方程组的最小非负整数解。
\[\begin{cases} x \equiv a_1\ ({\rm mod}\ m_1) \\ x\equiv a_2\ ({\rm mod}\ m_2) \\ ... \\ x \equiv a_n\ ({\rm mod}\ m_n)\end{cases}\]
其中\(m_i\)两两互质。
解法
我们贪心构造和式使得每一项在模意义下不影响其他项,并且符合当前的方程,
设\(M =\prod^{n}_{i=1}m_i,M_i=\frac{M}{m_i}\),可以构造解
\[x=\sum^{n}_{i=1}M_i(a_iM_i^{-1} \mod m_i)\]
可以证明解在模M 意义下唯一。
模板题:P3868 [TJOI2009]猜数字
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int INF=1e9+7,MAXN=11; inline LL mult(LL a,LL b,LL mod){ LL ret=0; while(b>0){ if(b&1) ret=(ret+a)%mod; a=(a+a)%mod; b>>=1; } return ret; } void exgcd(LL a,LL b,LL &x,LL &y){ if(!b){ x=1; y=0; return; } exgcd(b,a%b,y,x); y-=a/b*x; } inline LL inv(LL x,LL p){ LL a,b; exgcd(x,p,a,b); return (a%p+p)%p; } int N; LL a[MAXN],b[MAXN],M,lcm=1,ans; int main(){ scanf("%d",&N); for(int i=1;i<=N;i++) scanf("%lld",a+i); for(int i=1;i<=N;i++){ scanf("%lld",b+i); lcm*=b[i]; a[i]=(a[i]%b[i]+b[i])%b[i]; } for(int i=1;i<=N;i++){ LL Mi=lcm/b[i],t=inv(Mi,b[i]); ans=(ans+mult(mult(Mi,t,lcm),a[i],lcm))%lcm; } printf("%lld",(ans+lcm)%lcm); return 0; }
扩展中国剩余定理EXCRT
形式
给定 \(n\) 组非负整数 \(m_i, a_i\) ,求解关于 \(x\) 的方程组的最小非负整数解。
\[\begin{cases} x \equiv a_1\ ({\rm mod}\ m_1) \\ x\equiv a_2\ ({\rm mod}\ m_2) \\ ... \\ x \equiv a_n\ ({\rm mod}\ m_n)\end{cases}\]
解法
扩展中国剩余定理的方法和中国剩余定理关系不大,我们贪心处理前\(i-1\)项,然后合并当前方程。
将每个方程拆成若干个方程
\[x=a_i(\mod p_{i,j}^{k_{i,j}})\]
其中\(m_i=\prod p_{i,j}^{k_{i,j}}\)为\(m_i\) 的分解式。对每个质数\(p\),合并对应的所有方程,从而转化为模数两两互质的情形。若合并过程中出现矛盾,则原方程组无解。
模板题:P4777 【模板】扩展中国剩余定理(EXCRT)
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int INF=1e9+7,MAXN=1e5+10; inline LL mult(LL a,LL b,LL mod){ LL ret=0; while(b>0){ if(b&1) ret=(ret+a)%mod; a=(a+a)%mod; b>>=1; } return ret; } LL exgcd(LL a,LL b,LL &x,LL &y){ if(!b){ x=1; y=0; return a; } LL ret=exgcd(b,a%b,y,x); y-=a/b*x; return ret; } int N; LL a[MAXN],b[MAXN],M,ans,x,y; int main(){ scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%lld%lld",b+i,a+i); a[i]=(a[i]%b[i]+b[i])%b[i]; } M=b[1]; ans=a[1]; for(int i=2;i<=N;i++){ LL rm=(a[i]-ans%b[i]+b[i])%b[i]; LL gcd=exgcd(M,b[i],x,y); LL bg=b[i]/gcd; /*if(rm%gcd):ERROR*/ x=mult(x,rm/gcd,bg); ans+=x*M; M*=bg; ans=(ans%M+M)%M; } printf("%lld",ans); return 0; }
来源:https://www.cnblogs.com/guoshaoyang/p/11296138.html