一、逆元理解
逆元是什么?
逆元就是扩大了概念的倒数。
定义:如果 ax≡1(mod M),就称x为在模M下 a的 逆元!
简单地说,如果一个数x满足 ax%M=1,那么x就称为在模M下 a的 逆元!
为什么说是扩大了概念的倒数呢,可见比起以前的倒数,只加了一个条件,即在后边加了一个 “%M",也可以这样理解,我们以前的倒数,也有这个条件,不过M是1。
二、逆元用处
有时候结果会让取模,除法只能用逆元取,如下:
(a/b)%M=(ainv[b])%M=(a%M)(inv[b]%M)%M
三、方法
(一、费马小定理)
费马小定理:
如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1(mod p)。 [1]
局限性:只能用于p为素数,且gcd(a,p)为1
改造一下费马小定理式子得到:a*a^(p-2)≡1(mod p)
这样,便和逆元式子对应起来了,a的逆元便是x,即是a^(p-2)
用快速幂就OK了
int quick(int a,int n,int p)
{
if(n==0)
return 1;
if(n%2)
return a*quick(a,n-1,p)%p;
int tmp=quick(a,n/2,p);
return tmp*tmp%p;
}
(二、扩展欧几里得定理)
局限性:gcd(a,M)=1,但并不要求M为素数,所以这个适用范围更广泛,而且稍快,推荐
ax≡1(mod M)
ax-My=1
即:ax+My=1
void exgcd(int a,int b,int &g,int &x,int &y)
{
if(!b)
{
g=b; x=1; y=0;
}
else
{
exgcd(b,a%b,g,y,x); y-=x*(a/b);
}
}
(三、线性推)
inv[1] = 1;
for(int i = 2; i < p; ++ i)
inv[i] = (p - p / i) * inv[p % i] % p;