中国剩余定理和扩展中国剩余定理
作者:互联网
中国剩余定理
定理
\[f(x)=\begin{cases}x \equiv a_1\pmod{m_1}\\x \equiv a_2\pmod{m_2}\\.\\.\\.\\x \equiv a_n\pmod{m_n}\end{cases}其中:m_1,m_2,m_3...,m_n 互质。 \]且 \(M=\prod\limits_{i=1}^{n}m_i,M_i=\frac{M}{m_i},t_i=M_i^{-1}\),\(t_i\) 是在模 \(m_i\) 意义下的乘法逆元
则有最小解 \(x=(\sum\limits_{i=1}^{n}a_it_iM_i)\% M\)
证明
简易说明
\[\begin{align} \notag &M=\prod\limits_{i=1}^{n}m_i,M_i=\frac{M}{m_i},t_i=M_i^{-1}\\\notag &则可以构造出一解 x=a_1t_1M_1+a_2t_2M_2+..+a_nt_nM_n+kM=kM+\sum\limits_{i=1}^{n}a_it_iM_i,k\in Z\\\notag &\iff x_{min}=(\sum\limits_{i=1}^{n}a_it_iM_i)\% M \end{align} \]证明 \(\sum\limits_{i=1}^{n}a_it_iM_i\) 是一个解
\[\begin{align} \notag &对于任意一个方程 x\equiv a_i\pmod{m_i}~来说\\\notag &x\% m_i=(a_1t_1M_1+a_2t_2M_2+..+a_nt_nM_n)\% m_i=a_it_iM_i\% m_i+\sum\limits_{j=1,j!=i}^{n}a_jt_jM_j\% m_i\\\notag &\because 当j!=i时m_i|M_j~~~~~~~注:这就是为什么必须要保证m互质,同时也证明了若互质则必定有解\\\notag &\therefore x_i\%m_i=a_it_iM_i\%m_i\\\notag &又\because t_iM_i\equiv 1\pmod{m_i}\\\notag &\therefore x_i\%m_i=a_i\%m_i\\\notag &\therefore x_i\equiv a_i\pmod{m_i} \end{align} \]证明\(kM+\sum\limits_{i=1}^{n}a_it_iM_i,k\in Z\) 是一个解以及最小解
\[\begin{align} \notag &同上理,x=kM+\sum\limits_{i=1}^{n}a_it_iM_i,k\in Z 必然为方程的一个解\\\notag &\therefore 两个解相差 kM,k\in Z\\\notag &\therefore 对于非负数解集 Q 来说,是以 (\sum\limits_{i=1}^{n}a_it_iM_i)\% M 为首项,M为公差的等差数列 \end{align} \]代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn = 423;
ll int_maxn=1e9;
ll ll_maxn=1e18;
const ll mod=1e9+7;
const ll cs=998244353;
inline ll read_int(){
ll a=0,f=0,g=getchar();
while(g<'0'||g>'9'){if(g=='-') f=1;g=getchar();}
while('0'<=g&&g<='9') a=a*10+g-'0',g=getchar();
return f ? -a : a;
}
inline void write(ll s,bool f){
int top=0,a[40];
if(s<0) s=-s,putchar('-');
while(s) a[++top]=s%10,s/=10;
if(top==0) a[++top]=0;
while(top) putchar(a[top]+'0'),top--;
if(f) putchar('\n');
}
ll n;
ll A[maxn],M[maxn];
ll T[maxn],MM[maxn];
ll lin=1;
inline ll exgcd(ll a,ll b,ll & x,ll & y){
if(b==0){x=1,y=0;return a;}
ll gcd=exgcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
}
inline void read(){
n=read_int();
for(ll i=1;i<=n;i++) M[i]=read_int(),A[i]=read_int(),lin*=M[i];
for(ll i=1;i<=n;i++) MM[i]=lin/M[i];
ll ans=0;
ll x,y;
for(ll i=1;i<=n;i++) exgcd(MM[i],M[i],x,y),T[i]=(x%M[i]+M[i])%M[i];
for(ll i=1;i<=n;i++) ans=(ans+(A[i]*T[i]*MM[i]%lin+lin)%lin)%lin;
write(ans,1);
}
int main (){
read();
}
扩展中国剩余定理
说明:中国剩余定理和扩展中国剩余定理只有名字相似罢了,思路基本不同!!
求解方程
\[f(x)=\begin{cases}x \equiv a_1\pmod{m_1}\\x \equiv a_2\pmod{m_2}\\.\\.\\.\\x \equiv a_n\pmod{m_n}\end{cases} 其中:m_1,m_2,m_3...,m_n$ 不互质 \]思路推导
由于不保证 \(m_1,m_2,m_3..,m_n\) 互质,所以考虑将方程两个两个合并起来依次求解(可能无解)
\[\begin{align} \notag &取前两个方程进行合并 \begin{cases} x\equiv a_1\pmod{m_1} \\ x\equiv a_2\pmod{m_2}\end{cases}\\\notag &\therefore x=a_1+y_1m_1~~y_1\in Z\\ &\therefore x=a_2+y_2m_2~~y_2\in Z\\\notag &\Rightarrow y_2m_2-y_1m_1=a_1-a_2\\\notag &\therefore 当\gcd(m_1,m_2)|a_1-a_2 时有解,反之无解\\\notag &假设有解,则令 d=\gcd(m_1,m_2)\\\notag &\therefore \frac{m_2}{d}y_2-\frac{m_1}{d}y_1=\frac{a_1-a_2}{d}~~~~~~~~~注:裴储定理 \\\notag &\therefore \frac{m_2}{d}y_2\equiv \frac{a_1-a_2}{d}\pmod{\frac{m_1}{d}} \\\notag &\because \frac{m_2}{d}\perp\frac{m_1}{d} \therefore 令 inx[\frac{m2}{d}]为模\frac{m1}{d}意义下的乘法逆元~~~~~~~~~~~注:\frac{m_2}{d}\perp\frac{m_1}{d}是为了保证又乘法逆元 \\\notag &\therefore inx[\frac{m_2}{d}]\frac{m_2}{d}y_2\equiv \frac{a_1-a_2}{d}inx[\frac{m_2}{d}]\pmod{\frac{m_1}{d}} \Rightarrow y_2\equiv inx[\frac{m_2}{d}]\frac{a_1-a_2}{d}\pmod{\frac{m_1}{d}}\\ &\iff y_2=inx[\frac{m_2}{d}]\frac{a_1-a_2}{d}+y\frac{m_1}{d}\\ \notag &(1)(2)\Rightarrow x=a_2+m_2inx[\frac{m_2}{d}]\frac{a_1-a_2}{d}+y\frac{m_1m_2}{d} \\\notag &\therefore 方程~x\equiv a_2+m_2inx[\frac{m_2}{d}]\frac{a_1-a_2}{d} \pmod{\frac{m_1m_2}{d}} ~的解为上述方程组的解 \\\notag & 同理 x\equiv a_1+m_1inx[\frac{m_1}{d}]\frac{a_2-a_1}{d} \pmod{\frac{m_1m_2}{d}} 的解也为方程组的解 \end{align} \]注意:在写代码时,注意变量名
CODE
#include<bits/stdc++.h>
#define ll __int128
using namespace std;
const ll maxn = 423;
ll int_maxn=1e9;
ll ll_maxn=1e18;
const ll mod=1e9+7;
const ll cs=998244353;
inline ll read_int(){
ll a=0,f=0,g=getchar();
while(g<'0'||g>'9'){if(g=='-') f=1;g=getchar();}
while('0'<=g&&g<='9') a=a*10+g-'0',g=getchar();
return f ? -a : a;
}
inline void write(ll s,bool f){
ll top=0,a[40];
if(s<0) s=-s,putchar('-');
while(s) a[++top]=s%10,s/=10;
if(top==0) a[++top]=0;
while(top) putchar(a[top]+'0'),top--;
if(f) putchar('\n');
}
ll n;
ll a1,a2,m1,m2;
ll ans;
inline ll exgcd(ll a,ll b,ll& x,ll& y){
if(!b){x=1,y=0;return a;}
ll gcd=exgcd(b,a%b,y,x);
y-=a/b*x;
return gcd;
}
inline bool Extended_Chinese_remainder_theorem(){
ll x,y;
ll d=exgcd(m1,m2,x,y);
ll c=a2-a1;
if(c%d) return 0;
x=((c/d*x)%(m2/d)+m2/d)%(m2/d);
ll mod=m1/d*m2;
a1=((m1*x+a1)%mod+mod)%mod;
m1=mod;
return 1;
}
inline void read(){
n=read_int();
a1=read_int(),m1=read_int();
for(ll i=1;i<n;i++){
a2=read_int(),m2=read_int();
if(!Extended_Chinese_remainder_theorem()) {write(-1,0);return;}
}
write(a1%m1,1);
}
int main (){
read();
}
总结有以下毒瘤之处:
- 注意时刻保证\(a_1,m_1\) 处于正确的范围之中
- 注意判断无解条件 \(a_2-a_1\% d~!=0\)
- 多开
__int128
- 一定要熟练运用裴储定理以及同余性质!
标签:剩余,frac,pmod,定理,扩展,notag,therefore,ll,equiv 来源: https://www.cnblogs.com/LQX-OI/p/16379701.html