学习笔记 - 数论/数学 - 乘法逆元
zjcOvO
·
·
个人记录
对于本篇文章,看这个就够了:https://oi-wiki.org/math/number-theory/inverse/
感觉本算法的应用比较广一些。
求法:
| | | |
| :- | :-: | -: |
| 求 $i^{-1}\quad(1\le i\le n)$ | $\Theta(n)$ | [线性求从 1 开始连续 n 个数的逆元](https://oi-wiki.org/math/number-theory/inverse/#_5)|
| 求 $i^{-1}\quad i \in s\ (s\subseteq[1,b]\,)$ | $\Theta(\left\vert s\right\vert+\log b)$ | [线性求任意 n 个数的逆元](https://oi-wiki.org/math/number-theory/inverse/#n) |
| 求 $a^{-1}\quad \gcd(a,b)=1$ | $O(\log(\min(a,b)))$ | [扩展欧几里得法](https://oi-wiki.org/math/number-theory/gcd/#_7)
| 求 $a^{-1}\quad \gcd(a,b)=1 $ 要求 $b \in \text{prime}$ |$\Theta(\log b)$ | [快速幂法](https://oi-wiki.org/math/number-theory/inverse/#_4) #不推荐|
---
## 线性求从 1 开始连续 n 个数的逆元
### 先上结论:
$$i^{-1}\equiv\begin{cases}\text{undifined},&i=0\\1,&i=1\\-\left\lfloor\dfrac p i \right\rfloor\cdot(p\bmod i)^{-1},&\text{otherwise}\end{cases}$$
### 证明:
$\because 1\cdot1=1\equiv1\pmod p\qquad\qquad\qquad\therefore 1^{-1}\equiv1\pmod p
\because\left\lfloor\dfrac p i \right\rfloor\cdot i\,+\,(p\bmod i)\equiv0\pmod p\quad\therefore\left\lfloor\dfrac p i \right\rfloor\cdot(p\bmod i)^{-1}\,+\,i^{-1}\equiv0\pmod p
代码
void getInv(int n,int p){//get inv[1~n] (mod p)
inv[1]=1;for(int i=2;i<=n;i++)
inv[i]=(ll(p-p/i)*inv[p%i])%p;
}
线性求任意 n 个数的逆元
先通过一次扫描扫出 n 个数前缀乘积数组 S
然后通过扩展欧几里得法或快速幂法求出 S_n^{-1}
然后从后往前递推求出前缀逆元乘积数组 S^{-1}
依靠 a_i^{-1}=\dfrac{S_i^{-1}}{S_{i-1}} 求出 a^{-1}
代码
int s[5000005],r[5000005]; //r->s^{-1}
int* getInv(int* __first,int* __last,int p){
s[0]=1;for(int i=1;i<=(__last-__first);++i)s[i]=(ll(s[i-1])**(__first+i-1))%p;
int y;exgcd(s[__last-__first],p,r[__last-__first],y);r[__last-__first]=(r[__last-__first]%p+p)%p;
for(int i=__last-__first;i>=1;i--)r[i-1]=(ll(r[i])**(__first+i-1))%p;
for(int i=1;i<=__last-__first;i++)inv[i]=(ll(s[i-1])*r[i])%p;return inv+1;
}