oi-wiki
Version:
wiki for OI / ACM-ICPC
95 lines (62 loc) • 2.08 kB
Markdown
## 逆元简介
如果一个线性同余方程 $ax \equiv 1 \pmod b$,则 $x$ 称为 $a \mod b$ 的逆元,记作 $a^{-1}$。
## 如何求逆元
### 扩展欧几里得法:
```cpp
void ex_gcd(int a,int b,int&x,int&y)
{
if(b==0)
{
x=1,y=0;
return;
}
ex_gcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return;
}
```
扩展欧几里得法和求解 [线性同余方程](/math/linear-equation/) 是一个原理,在这里不展开解释。
### 快速幂法:
这个要运用 [费马小定理](https://oi-wiki.org/math/fermat/):
> 若 $p$ 为质数,$a$ 为正整数,且 $a$、$p$ 互质,则 $a^{p-1} \equiv 1 \pmod p$。
因为 $ax \equiv 1 \pmod b$;
所以 $ax \equiv a^{b-1} \pmod b$(根据费马小定理);
所以 $x \equiv a^{b-2} \pmod b$;
然后我们就可以用快速幂来求了。
代码:
```cpp
#define ll long long
inline ll poW(ll a,ll b){
long long ans=1;
a%=p;
while (b){
if (b&1) ans=((ans*a)%p+p)%p;
a=(a*a)%p; b>>=1;
}
return ans%p;
}
```
### 线性求逆元
但是如果要求的很多,以上两种方法就显得慢了,很有可能超时,所以下面来讲一下如何线性求逆元。
首先,很显然的 $1^{-1} \equiv 1 \pmod p$;
然后,设 $p=ki+j,j<i,1<i<p$,再放到 $\mod p$ 意义下就会得到:$ki+j \equiv 0 \pmod p$;
两边同时乘 $i^{-1},j^{-1}$:
$kj^{-1}+i^{-1} \equiv 0 \pmod p$;
$i^{-1} \equiv -kj^{-1}+ \pmod p$;
$i^{-1} \equiv -(\frac{p}{i}) (p \mod i)^{-1}$;
然后我们就可以推出逆元了,代码只有一行:
```cpp
a[i]=-(p/i)*a[p%i];
```
但是,有些情况下要避免出现负数,所以我们要改改代码,让它只求正整数:
```cpp
a[i]=(p-p/i)*a[p%i]%p;
```
这就是线性求逆元
## 逆元练习题
[【模板】乘法逆元](https://www.luogu.org/problemnew/show/P3811)
[同余方程](https://www.luogu.org/problemnew/show/P1082)
[\[AHOI2005\] 洗牌](https://www.lydsy.com/JudgeOnline/problem.php?id=1965)
[\[SDOI2016\] 排列计数](https://www.luogu.org/problemnew/show/P4071)