同余问题学习笔记
同余问题学习笔记
——by sunzz3183
扩展欧几里得(exgcd)
命题
对于两个正整数 \(a,b\),存在两个整数 \(x,y\) 使得
证明
在欧几里得算法的最后一步,即 \(b=0\) 时,显然 \(x=1,y=0\),使得 \(a\times 1+0\times 0=gcd(a,0)\)。
若 \(b>0\) ,则,\(gcd(a,b)=gcd(b,a \bmod b)\)。假设存在一对整数 \(x,y\),满足
因为
所以令 \(x^{\prime}=y,y^{\prime}=x-\left \lfloor \frac{a}{b} \right \rfloor y\),就得到了 \(ax^{\prime}+by^{\prime}=gcd(a,b)\)
证毕
代码
inline int exgcd(int a,int b,int &x,int &y){
if(!b){x=1;y=0;return a;}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
通式
则对于任意一个
当 \(gcd(a,b)|c\) 时,等式成立。
则此时
通解
设二元一次不定方程
有一组整数解 \(x=x_0,y=y_0\),则一切整数解可以表示成
其中 $t=0,\pm 1,\pm 2,\pm 3,\cdots $
证明
既然 \(x_0,y_0\) 为整数解,当然满足 \(ax_0+by_0=c\),因此
设 \(x^{\prime },y^{\prime }\) 为任意一组整数解,则有 \(ax^{\prime }+by^{\prime }=c\),减去 \(ax_0+by_0=c\),即得
所以我们得到
即
将
代入
即得
因此
$ x^{\prime },y^{\prime }$ 可表示成 \(x^{\prime }=x_0-\frac{bt}{\gcd (a,b)},y^{\prime }=y_0+\frac{at}{\gcd (a,b)}\) 的形式
所以
为 \(ax+by=c\) 的一切整数解
证毕
中国剩余定理(CRT)
命题
已知同余式组
其中 \(b\in \mathbb{N} ,m\in \mathbb{N^* } ,m_i \perp m_j\)
求 \(x\)
求法
令
则同时满足同余式组
的正整数解是
这里的 \(M_i^{\prime}\) 是满足同余式
的正整数解
证明
因为 \(m_i \perp m_j,M_i=\frac{M}{m_i}\),所以 \(m_i \perp M_i\),所以
由扩展欧几里得可得,存在两个整数 \(M_i^{\prime},n_i\),使得
所以存在一个 \(M_i^{\prime}\),使得
又由当 \(i\ne j\)时,则由 \(m_i \perp m_j,M_j=\frac{M}{m_j}\) 得到 \(m_i|M_j\),所以
所以
设 \(y\) 为同余式组的一个整数解,则得
也就是
又因为 \(m_i \perp m_j\),所以有 \(M|(x-y)\),也就是
所以
是满足同余式组的唯一正整数解
证毕
代码
inline int exgcd(int a,int b,int &x,int &y){
if(!b){x=1;y=0;return a;}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
int CRT(int A[],int B[],int k){
int x,y,a=0,m,n=1;
for(int i=1;i<=k;i++)n*=A[i];
for(int i=1;i<=k;i++){
m=n/A[i];
exgcd(A[i],m,x,y);
(a+=y*m*B[i])%=n;
}
return (a+n)%n;
}
扩展中国剩余定理(exCRT)
命题
已知同余式组
其中 \(b\in \mathbb{N} ,m\in \mathbb{N^* }\)
求 \(X\)
与 \(CRT\) 不同的是,这个 \(m_i,m_j\),不一定两两互质。
求法
(建议配合代码食用)
考虑合并
可以写成
所以
整理,得
通过 \(exgcd\) 可以得到一组解 \(x_0,y_0\)
所以
因为 \(X=m_1x+b_1\),现在要最小化 \(X\),也就是最小化 \(x\),即最小化 \(x=x_0\frac{b_2-b_1}{\gcd(m_1,m_2)}\)
我们假设 \(b_2,m_2\),为已经算出的前 \(k\) 对数的答案
于是就可以将这两个同余方程合并为
代码
inline int exgcd(int a,int b,int &x,int &y){
if(!b){x=1;y=0;return a;}
int d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
int exCRT(int *A,int *B,int k){
int x,y,a=A[1],ans=B[1];
for(int i=2;i<=k;i++){
int b=A[i],c=((B[i]-ans)%b+b)%b,d=exgcd(a,b,x,y);
if(c%d)return -1;
x=(__int128)x*(__int128)c/(__int128)d%(b/d);
ans+=a*x;
a=a/d*b;
ans=(ans%a+a)%a;
}
return (ans%a+a)%a;
}