[数论] exgcd & 逆元
前置知识
欧几里得算法
我们首先了解一下朴素欧几里得算法(辗转相除法)。
定理:\(\gcd(a,b)=\gcd(b,a\%b)\)、
简要证明
令 \(a=kb+r,d|a,d|b\)(即 \(d\) 是 \(a,b\) 的任意一个公因数),且 \(a,k,b,r\) 均为正整数,\(r\ne 0\).
由 \(a=kb+r\) 得 \(r=a-kb\). 且 \(a\%b=r\).
等式左右同除以 \(d\),得 \(\frac{r}{d}=\frac{a}{d}-k\frac{b}{d}\).
\(∵d|a,d|b\)
\(∴\frac{a}{d}-k\frac{b}{d}\) 为正整数.
即 \(\frac{r}{d}\) 为正整数.
\(∴ d|r\)
所以对于 \(\forall d\),都满足 \(d|(a\%b),d|b\),得证.
运用欧几里得算法我们可以在 \(O(\log n)\) 的时间复杂度内求出任意两数的 \(\gcd\).当然常用的 __gcd
库也运用了欧几里得算法.
__gcd 函数内容 供参考
template<typename _Mn, typename _Nn>
constexpr common_type_t<_Mn, _Nn>
__gcd(_Mn __m, _Nn __n)
{
return __m == 0 ? __detail::__abs_integral(__n)
: __n == 0 ? __detail::__abs_integral(__m)
: __detail::__gcd(__n, __m % __n);
}
裴蜀定理
定理1
有 \(a,b\in \mathbb{Z}\),那么一定存在整数 \(x,y\) 使得 \(ax+by=\gcd(a,b)\).
证明
我们只需证明 已知 \(x',y'\) 是方程 \(bx+(a\mod b)y=d\) 时的一组特解,能够求出 \(ax+by=d\) 的解 即可.
已知
显然成立.
将上式代入方程 \(bx+(a\mod b)y=d\),得:
提公因式,得:
注意到上式与方程 \(bx+(a\mod b)y=d\) 是等价的,即得
由此我们证明,若已知方程 \(bx+(a\mod b)y=d\) 的解,能够求出 \(ax+by=d\) 的解.而我们在欧几里得算法中,证明了 \(\gcd(a,b)=\gcd(b,a\%b)\),递归求解到 \(a\%b=0\) 时求解出当前方程唯一解,层层回溯即可求出方程 \(ax+by=\gcd(a,b)\) 的解.证毕.
定理2
若方程 \(ax+by=c\) 有整数解,则方程满足 \(\gcd(a,b)|c\),否则方程无整数解.
证明
设 \(a=p\times \gcd(a,b),b=q\times \gcd(a,b)\).
代入方程得:
提取公因式,得:
\(c=(px+py)·\gcd(a,b)\)
已知 \(x,y\) 为整数,得:
\(\gcd(a,b)|c\).
证毕.
定理3
若 \(ax+by=1\) 存在整数解,那么 \(\gcd(a,b)=1\),即 \(a,b\) 互质.
证明
同样设 \(a=p\times \gcd(a,b),b=q\times \gcd(a,b)\).
代入方程得:
方程两边同除以 \(\gcd(a,b)\),得:
因此,若 \(\gcd(a,b)>1\),即 \(a,b\) 不互质,\(px+qy<1\),因为 \(p,q\) 为正整数,故方程不存在整数解.证毕.
exgcd
事实上,在裴蜀定理1中,我们的证明过程即为 exgcd 的求解过程。
exgcd 通常解决类似于这样的问题,给定 \(a,b\in\mathbb{N^*},d=\gcd(a,b)\),求方程 \(ax+by=d\) 的一组整数解.
这里给出 exgcd 的模板代码.
#include <bits/stdc++.h>
#define LL long long
using namespace std;
void exgcd(int a, int b, LL &x, LL &y)//注意 x 跟 y 是引用,因为要修改
{
if (b == 0) {x = 1; y = 0; return ;} // gcd 算到头,准备回溯
exgcd(b, a % b, x, y);
LL p = x; x = y; y = p - ((LL)a / b) * y;//回溯的时候套用裴蜀定理1中推导出来的公式
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>a;
cin>>b;
LL x = 0, y = 0;
exgcd(a, b, x, y);
cout<<x<<" "<<y<<endl;
return 0;
}
逆元
定义 & 存在性
众所周知,形如 \(a+b,a-b,a\times b\) 式子取模,我们都可以转化成 \(a\bmod p +b\bmod p\) 形式。也就是可在任意位置进行取模而不改变运算结果。
但对于除法运算,\(\dfrac{a}{b}\bmod p \ne \dfrac{a\bmod p}{b\bmod p}\)。
我们尝试找到一个数 \(b_{inv}\),使得 \(\dfrac{a}{b}\bmod p=(a\times b_{inv}\bmod p)\)。将除法转换为乘法进行运算。
定义:若满足 \(b\times b_{inv}\equiv 1(\bmod\space p)\),则称 \(b_{inv}\) 是 \(b\) 在 \(\bmod p\) 意义下的乘法逆元。
考虑何时乘法逆元 \(b_{inv}\) 存在。
设 \(b\times b_{inv}=k\times p+1\),\(g=\gcd(b,p)\)。我们转换如下。
(在上式中,\(g\times b_1=b, g\times p_1=p\)。)
简单转化得
由于我们讨论的范围是整数,故存在
以上各步骤均可逆,故乘法逆元存在 当且仅当 \(\gcd(b,p)=1\)。
求解
费马小定理
定理:若 \(p\) 为质数,则 \(a^{p-1}\equiv 1(\bmod\space p)\)。
回顾逆元定义:\(b\times b_{inv}\equiv 1(\bmod\space p)\)。
因此,若 \(p\) 为质数,则 \(b\times b^{p-2}\equiv 1(\bmod\space p)\)。
只需取 \(b_{inv}=b^{p-2}\) 即可。可使用快速幂算法加速。
扩展欧几里德算法 (exgcd)
回顾:\(\text{exgcd}\) 可求解 \(ax+by=\gcd(a,b)\) 的一组 \(x,y\)。
已知 \(a\times a_{inv}\equiv 1(\bmod\space p)\Leftrightarrow a\times a_{inv}+py=1\)。
前文提到,逆元存在当且仅当 \(a,p\) 互质。
故
应用 \(\text{exgcd}\) 求解即可。
线性求逆元
如何求解区间 \([1,n]\) 依次在 \(\bmod\space p\) 意义下的逆元?(保证 \(p\) 为质数。)
对于一个数 \(x\),满足 \(p>x\),设 \(p>kx+r,k=\lceil \dfrac{p}{x}\rceil,r=p\bmod \space x\)。
则
我们要求 \(x_{inv}\),而 \(x\times x_{inv}\equiv 1(\bmod\space p)\)。
我们首先要构造出 \(1\) 才能构造出 \(x_{inv}\)。
左右同除以 \(r\),得
因此,\(\dfrac{k}{r}x\equiv -x\times x_{inv}(\bmod\space p)\),继而得
即 \(x_{inv}\equiv -k\times r_{inv}\)
因此,若我们已知 \(r_{inv}\) 的值,我们就能得到 \(x_{inv}\) 的值。
前文提到 \(r=p\bmod\space x<x\),因此在依次求 \([1,n]\) 的逆元时, \(r_{inv}\) 一定在 \(x_{inv}\) 前求出。上式即为递推式。
本文作者:SXqwq,转载请注明原文链接:https://www.cnblogs.com/SXqwq/p/18286786/exgcd