一、定义
乘法逆元:
这里,我们称 x 是 a 关于 m 的乘法逆元 ,等价为不定方程组: ax + my = 1
二、作用
求 (b/a) % m的值
由同余定理知
a*b%m=( (a%m) * (b%m) )%m
则有 a*x*(b/a)%m=( (a*x%m) * ((b/a)%m) )%m=(b/a)%m (x是a的逆元所以a*x%m=1)
故 a*x*(b/a)%m=x*b%m=(b/a)%m
即原式子等于分子乘以分母的逆元再对m取模
三、求逆元的方法(前3种方法讨论当模数为素数的情况,因为如果模数不为素数,则不一定每个数都有逆元。)
方法一:扩展欧几里得
由不定方程组 ax + by = c 有解的充要条件: c % gcd(a , b) = 0,可知上述方程有解的条件是 gcd(a , m) = 1,即a和m互质
有很多组解满足条件,但是一般是求解出最小的那组解即可,通过扩展欧几里得可以求出一个特殊的解 ,又由x的通解
可知, a 关于 m 的逆元是一个关于 m 同余的,根据最小整数原理,一定存在一个最小的正整数,它是 a 关于m 的逆元,而最小的肯定是在(0 , m)之间的,而且只有一个,且为
特殊情况:
1.当 m 是负数的时候,对 m 取绝对值
2.当 x0 是负数的时候,它模上 m 的结果仍然是负数,先让 x0 对m取模,然后结果再加上m
int cal(int a,int m)
{
int x,y;
int gcd=e_gcd(a,m,x,y);
if(gcd!=1) return -1;
m=abs(m);
int ans=x%m;
if(ans<=0) ans+=m;
return ans;
}
方法二:费马小定理 + 快速模幂法
由费马定理知当p是质数,且gcd(a,p)=1时
即为
所以逆元为a^(p-2)当p较大时使用快速模幂法求解
方法三:递推法
有些题需要用到模的所有逆元,这里为奇质数。那么如果用快速幂求时间复杂度为,
如果对于一个10^6级别的素数,这样做的时间复杂度是很高了。实际上有的算法,有一个递推式如下
它的推导过程如下,设,那么
对上式两边同时除,进一步得到
再把和替换掉,最终得到
初始化,这样就可以通过递推法求出模奇素数的所有逆元了。
另外模的所有逆元值对应中所有的数,比如,那么对应的逆元是。
方法四:欧拉函数(适用于模数不是素数 )
由
得a的逆元为
练习:
51Nod_1256 乘法逆元【水题】