模素数意义下的乘法逆元
模意义下的乘法逆元
乘法逆元的定义
若 \(ax \equiv 1 \pmod p\),则称 \(x\) 为 \(a\) 在模 \(p\) 意义下的乘法逆元,记作 \(a^{-1}\)
当 \(p \in \mathbb{P}\) 时,求乘法逆元的方法:
利用费马小定理。
根据费马小定理,当 \(p\) 为素数时,有 \(a^{p-1} \equiv 1 \pmod p\)。
注意到 \(a \times a^{p - 2} \equiv a^{p - 1} \equiv 1 \pmod p\)。
故 \(a^{p - 2}\) 为 \(a\) 在模 \(p\) 意义下的一个逆元。
当 \(p \in \mathbb{P}\) 时,可以用快速幂来求逆元。
点击查看代码
LL QuickPower(LL a, LL b) {
LL ans = 1;
while (b) { if (b & 1) ans *= a; a *= a; b >>= 1; }
return ans;
}
int Inverse = QuickPower(a, p - 2);
线性求逆元
若求从 \(1\) 到 \(p\) 的逆元,可用该方法。
假设 \(1\) 到 \(i - 1\) 的逆元都已知。设 \(k = \left\lfloor\dfrac{p}{i}\right\rfloor, r = p \bmod i\)。则 \(ki + r \equiv 0 \pmod p\),两边同时除以 \(ir\),得 \(kr^{-1}+i^{-1} \equiv 0 \pmod p\),即 \(i^{-1} \equiv -kr^{-1}\equiv \left\lfloor\dfrac{p}{i}\right\rfloor \times (p \bmod i)^{-1}\)。
类似于 dp ,时间复杂度为 \(O(n)\)
点击查看代码
inv[1] = 1;
for (int i = 2; i <= p; i++) inv[i] = p / i + inv[p % i];
线性求 \(n\) 个数的逆元
求 \(n\) 个数的逆元可用此方法 \((1 \le a_i \lt p)\)。
设 \(s\) 为数组 \(a\) 的前缀积。计算出 \(s_n^{-1}\) 为 \(1\) 到 \(n\) 的逆元积,后通过 \(s_i^{-1} = s_{i + 1}^{-1} \times a_{i +1}\) 即可得到前 \(i\) 项逆元积,则 \(a_i^{-1} = s_{i - 1} \times s_i^{-1}\)
时间复杂度为 \(O(n + \log p)\)
点击查看代码
LL s[N], s_inv[N], a[N], a_inv[N];
int n, p;
LL QuickPower(LL a, LL b) {
LL ans = 1;
while (b) { if (b & 1) ans *= a; a *= a; b >>= 1; }
return ans;
}
cin >> n >> p;
s[0] = 1;
for (int i = 1; i <= n; i++) cin >> a[i], s[i] = a[i] * s[i - 1];
s_inv[n] = QuickPower(s[i], p - 2);
for (int i = n - 1; i >= 1; i--) s_inv[i] = s_inv[i + 1] * a[i + 1];
for (int i = 1; i <= n; i++) a_inv[i] = s[i - 1] * s_inv[i];
参考资料
你是个独立的人,无人能抹杀你的独立性,除非你向世俗妥协。