- 乘法逆元
乘法逆元
对于缩系中的元素,每个数a均有唯一的与之对应的乘法逆元x,使得 $math_inline$ax\equiv 1\left(\text{mod}n\right)$math_inline$ ,一个数有逆元的充分必要条件是gcd(a,n)=1,此时逆元唯一存在
在一般数学中,我们所说的逆元就是倒数,但是在数论中,如果一个数字a存在一个对p的逆元x,就可以写成 $math_inline$ax\equiv 1\left(\text{mod}p\right)$math_inline$ 的形式(此处p与a互质,若不互质,则不存在逆元)
逆元的含义:模n意义下,1个数a如果有逆元x,那么除以a相当于乘以x。
满足 $math_inline$a \times k\equiv 1(\text{mod}p)的k值就是a关于p的乘法逆元$math_inline$
当我们要求 $math_inline$\frac{a}{b}\text{mod}p$math_inline$ 的值时,我们就可以用到乘法逆元。我们可以用过求b关于p的乘法逆元k,将a乘上k再模p,即 $math_inline$(a \times k)\text{mod}p$math_inline$ 。其结果与 $math_inline$\frac{a}{b}\text{mod}p$math_inline$ 等价
证明
根据 $math_inline$b \times k\equiv 1(\text{mod}p)$math_inline$ 有 $math_inline$b \times k=p \times x+1$math_inline$
$math_inline$k=\frac{p \times x+1}{b}$math_inline$把k带入 $math_inline$(a \times k)\text{mod}p$math_inline$ 得
$math_inline$(\frac{a \times (p \times x+1)}{b})\text{mod}p$math_inline$ $math_inline$=(\frac{a \times p \times x}{b}+\frac{a}{b})\text{mod}p$math_inline$ $math_inline$=[(\frac{a \times p \times x}{b}\text{mod}p)+\frac{a}{b}]\text{mod}p$math_inline$ $math_inline$=[(\frac{p \times (a \times x)}{b}\text{mod}p)+\frac{a}{b}]\text{mod}p$math_inline$ $math_inline$//p \times [\frac{a \times x}{b}]\text{mod}p=0$math_inline$所以原式等于: $math_inline$\frac{a}{b}\text{mod}p$math_inline$
拓展欧几里得
**拓展欧几里得:** $math_inline$ax+by=\gcd(a,b)$math_inline$ 的解一定存在
当我们要求 $math_inline$a$math_inline$ 关于 $math_inline$p$math_inline$ 的逆元时,若逆元存在,则 $math_inline$\gcd(a,p)=1$math_inline$ 。假设逆元为 $math_inline$x$math_inline$ ,即: $math_inline$ax \equiv 1(\text{mod}p)$math_inline$
我们可以展开一下变成 $math_inline$ax=1+pk$math_inline$ ,由于 $math_inline$k$math_inline$ 可正可负,我们可以得到 $math_inline$ax+pk=1$math_inline$ ,其实就是 $math_inline$ax+by=\gcd(a,b)$math_inline$ 。
我们用拓展欧几里得求出一个最小的x就是 $math_inline$a$math_inline$ 关于 $math_inline$p$math_inline$ 的一个逆元。
求解:
现在我们已经有了 $math_inline$ax+by=\gcd(a,b)$math_inline$ 了。我们想试着求出一个特解 $math_inline$x$math_inline$ 。
根据欧几里得算法我们可以知道 $math_inline$\gcd(a,b)=\gcd(b,a\%b)$math_inline$ 。
而且我们可以看出 $math_inline$bx+(a\%b)y = \gcd(b,\%b)$math_inline$
由此我们可得:(由于两边 $math_inline$x$math_inline$ , $math_inline$y$math_inline$ 值不用,我们用 $math_inline$x'$math_inline$ 和 $math_inline$y'$math_inline$ 进行区分)
$math_inline$bx'+(a\%b)y'=ax+by$math_inline$我们想要把式子简化一下,可以从 $math_inline$a\%b$math_inline$ 入手,即 $math_inline$a\%b=a-\lfloor \frac{a}{b} \rfloor\times b$math_inline$ 。
所以我们可以化简得到 $math_inline$ax+by=bx'+(a-\lfloor \frac{a}{b} \rfloor\times b)y'$math_inline$
移项: $math_inline$ax+by=ay'+b(x'-\lfloor \frac{a}{b} \rfloor y')$math_inline$
系数相等,所以我们可以解得
$math_inline$ \begin{equation} \left\{ \begin{array}{lr} x=y' & \\ y=(x'-\lfloor \frac{a}{b} \rfloor y') & \end{array} \right. \end{equation} $math_inline$根据欧几里得算法,我们一直递归下去,总会到 $math_inline$a\%b=0$math_inline$
所以式子变成了 $math_inline$ax=\gcd(a,b)$math_inline$ 。此时我们取一个特解 $math_inline$x=1,y=0$math_inline$ 。然后往回推,就可以得到一开始的那个x。
此时解出来的 $math_inline$x$math_inline$ 就是 $math_inline$a$math_inline$ 关于 $math_inline$p$math_inline$ 的一个逆元。
PS:算法效率较高,常数较小,时间复杂度 $math_inline$O(\ln{n})$math_inline$
Code
void exgcd(LL a, LL b, LL &x, LL &y) {
if (b == 0) {
x = 1;y = 0;
} else {
exgcd(b, a%b, y, x);
y -= (a/b) * x;
}
}
void extgcd(LL a, LL b, LL &d, LL &x, LL &y) {
if (!b) {
d = a;
x = 1;
y = 0;
} else {
extgcd(b, a % b, d, y, x);
y -= x * (a / b);
}
}
LL inverse(LL a, LL n) {
LL d, x, y;
extgcd(a, n, d, x, y);
return d == 1 ? (x + n) % n : -1;
}
递推求阶乘逆元
我们经常会用到阶乘的逆元,我们可以考虑用费马小定理先求出最大的那个阶乘的逆元,然后再往回推
我们可以把 $math_inline$n!$math_inline$ 的逆元表示为 $math_inline$\left[n!\right]^{-1}$math_inline$ 。
我们要求 $math_inline$(n-1)!$math_inline$ 的逆元,我们可以考虑给 $math_inline$(n-1)!$math_inline$ 乘上一个 $math_inline$n$math_inline$ 把他变为 $math_inline$n!$math_inline$ 。
即 $math_inline$(n-1)!\times n\left[n!\right]^{-1} \equiv 1\text{mod}p$math_inline$
因此 $math_inline$\left[n!\right]^{-1}$math_inline$ 是 $math_inline$(n-1)!$math_inline$ 关于 $math_inline$p$math_inline$ 的一个逆元。
Code
void init() {
fact[0] = 1;
for (int i = 1; i < maxn; i++) {
fact[i] = fact[i - 1] * i %mod;
}
inv[maxn - 1] = power(fact[maxn - 1], mod - 2);
for (int i = maxn - 2; i >= 0; i--) {
inv[i] = inv[i + 1] * (i + 1) %mod;
}
}
费马小定理
在模为素数p的情况下,有费马小定理 $math_inline$a^{p-1}\equiv 1(\text{mod}p)$math_inline$ ,(左右同除a)得 $math_inline$a^{p-2}=a^{-1}(\text{mod}p)$math_inline$ ,也就是说a的逆元为 $math_inline$a^{p-2}$math_inline$
符号解释
既约 $math_inline$\perp$math_inline$ , $math_inline$a\perp m$math_inline$ ,a与m既约、不可约、互素:
既约,或称不可约,或称互质,或称互素,a,m既约,记做 $math_inline$a \perp m$math_inline$ 或 $math_inline$(a,m)=1$math_inline$ 即a,m二者的最大公约数为1,已经约去公因子到不可再约了。
而在模数不为素数p得情况下,有欧拉定理 $math_inline$a^{phi(m)}\equiv q (\text{mod}m)\quad(a \perp m)$math_inline$
同理 $math_inline$a^{-1}=a^{phi(m)-1}$math_inline$
因此逆元x便可以套用快速幂求得了 $math_inline$x=a^{phi(m)-1}$math_inline$
如何判断a是否有逆元?检验逆元的性质,看求出的幂值x与a相乘是否为1即可
PS:这种算法复杂度为 $math_inline$O(\log_2(N))$math_inline$ 在几次测试中,常数似乎较上种方法大
当p比较大的时候需要用快速幂求解
Code
LL pow_mod(LL x, LL n, LL mod) {
LL res = 1;
while (n > 0) {
if (n & 1)res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
当模p不是素数的时候需要用到欧拉定理
$math_inline$a^{phi(p)}\equiv 1 \quad (\text{mod}p)$math_inline$ $math_inline$a \times a^{phi(p)-1}\equiv 1 \quad (\text{mod}p)$math_inline$ $math_inline$a^{-1}\equiv a^{phi(p)-1} \quad (\text{mod}p)$math_inline$所以时间复杂度即求出单个欧拉函数的值
(当p为素数的时候 $math_inline$phi(p)=p-1$math_inline$ ,则 $math_inline$phi(p)-1=p-2$math_inline$ 可以看出欧拉定理是费马小定理的推广)
PS:这里就贴出欧拉定理的板子,很少会用欧拉定理求逆元