定义
当 a b = c \frac{a}{b}=c ba=c时,可以看成是 a × b − 1 = c a\times b^{-1}=c a×b−1=c。令 x = b − 1 x=b^{-1} x=b−1,即有 a × x = c a \times x=c a×x=c, x x x为 b b b的逆元。
当计算都在模 p p p下意义下时,对于分数,负数是不能直接取模的,因此负数需要加上 p p p,而分数则由分子乘以分母的逆元,然后再对积取模。
计算逆元有三个方法:
扩展欧几里得
单个查找效率很高,尤其是当mod
p
p
p较大的时候。
利用扩展欧几里得求解线性同余方程
a
×
x
≡
c
m
o
d
b
a\times x\equiv c \mod b
a×x≡cmodb的c为1时的情况,转化出来的是:
a
×
x
+
b
×
y
=
1
a\times x+b\times y = 1
a×x+b×y=1
求解该方程的解。
ll x,y;
void exgcd(ll a,ll b){//最终的x为所求的逆元
if(b==0){
x = 1,y = 0;
return 0;
}
exgcd(b,a%b);
ll k;
k = x;
x = y;
y = k-(a/b)*y;
}
快速幂
这里需要引用费马小定理。
若 p p p为素数,a为正整数,且 a , p a,p a,p互质,则有 a p − 1 ≡ 1 m o d p a^{p-1}\equiv 1\mod p ap−1≡1modp
那么对于
a
×
x
≡
1
m
o
d
p
a\times x\equiv 1\mod p
a×x≡1modp
a
×
x
≡
a
p
−
1
m
o
d
p
a\times x\equiv a^{p-1}\mod p
a×x≡ap−1modp
x
≡
a
p
−
2
m
o
d
p
x \equiv a^{p-2} \mod p
x≡ap−2modp
即a一个数的逆元可以是其另一个与模数互质的因数的p-2次幂。
求解幂,可以采用快速幂的方法。
const int p ;//模数
ll qpow(ll a,ll b){//取逆元时,b = p-2即可
ll ans = 1;
while(b){
if(b&1) ans = ans*a%p;
b>>=1;
a*=a;
a%=p;
}
return ans;
}
线性算法
用于求一连串数字对于一个 m o d p \mod p modp的逆元只能用这个方法。其它的方法都要比打表慢一节。此处不做推导,直接给出结论。
a[i] = - (p/i) * a[p%i];//p为模数
a[i] = (a[i] % p + p)%p;
完整代码:
#include<iostream>
using namespace std;
typedef long long ll;
ll x,y,n,f[3000010];
int main(){
ll a,b,p,n,i;
cin >>n >> p;
f[1] = 1;
for(i = 2;i<=n;++i){
f[i] = -(p/i)*f[p%i];
f[i] = (f[i]%p+p)%p;
}
for(i = 1;i<=n;++i) cout<<f[i]<<'\n';//1~n的逆元
return 0;
}
通常来说,第二种快速幂的计算逆元的方法最为常见。逆元在组合数求解,分数取余上使用较多。