逆元是什么?
每个数a均有唯一的一个与之对应的乘法逆元x,使得(a * x)%m = 1
一个数有逆元的充分必要条件是gcd(a,m)=1,此时逆元唯一存在
逆元的含义:模m意义下,1个数a如果有逆元x,那么对于一个数k有k/a=k*x
方法一: 最简便的方法
最简便的一种方法是
方法二: 费马小定理
还是上面的例子, 因为除数可能会很大,超过int范围,所以如果当除数特别大的时候就需要求逆元
如果我告诉你我知道 1bmodm 1 b m o d m 的结果会怎么样,那么你就可以用 amodm1bmodm a m o d m 1 b m o d m 就可以得到结果了是不是?
这里 1bmodm 1 b m o d m 就是b相对于m的乘法逆元.
当然我们的费马大大和一众数学家不是这么理解的。费马小定理a ^ (p-1) = 1 (%p),两边同时除去a——a ^ (p-2) = a^-1 (%p),得a的逆元a^-1 = a ^ (p-2)。(参考自链接)。所以我们的(1/b)modm就是b^(mod-2)咯,用快速幂可以快速地完成这个工作。
下面用快速幂的方法来求逆元,但是这里的mod一定要是一个质数
ll inv(ll a,ll p)
{
ll m=p-2,ans=1;
while(m)
{
if(m&1) ans=ans*n%p;
m>>=1;
a=a*a%p;
}
return ans;
}
方法三: 扩展欧几里得
但是注意的是当mod是与不是质数的时候求的方法是不一样的,下面用扩展欧几里得求逆元是可以忽略mod是否质数的问题的
给定模数m,求a的逆相当于求解(a * x)%m = 1
这个方程可以转化为ax-my=1
然后套用求二元一次方程的方法,用扩展欧几里得算法求得一组x0,y0和gcd
检查gcd是否为1
gcd不为1则说明逆元不存在
若为1,则调整x0到0~m-1的范围中即可
//a对b求逆元
ll exgcd(ll a,ll b,ll &x,ll &y)
{
ll t,gcd;
if(b==0)
{
x=1,y=0;
return a;
}
gcd=exgcd(b,a%b,x,y);
t=x,x=y,y=t-a/b*y;
return gcd;
}
ll inv(ll a,ll b)
{
ll x,y;
exgcd(a,b,x,y);
x%=b;
x=(x+b)%b;
return x;
}
int main(){
ll x,y;//x和y不需要进行初始化
exgcd(a,b,x,y);
//(x+m)%m即是a相对于b的乘法逆元
}