逆元的几种求法

乘法逆元的定义貌似是基于群给出的,比较简单地理解,可以说是倒数的概念的推广。
记 a 关于模 p 的逆元为 a − 1 a^{-1} a1 ,则 a − 1 a^{-1} a1 满足 a a − 1 ≡ 1 ( m o d p ) aa^{-1}≡ 1 \pmod p aa11(modp)

加减乘与模运算的顺序交换不会影响结果,但是除法不行。有的题目要求结果mod一个大质数,如果原本的结果中有除法,比如除以a,那就可以乘以a的逆元替代。

在mod p的运算中,a存在乘法逆元当且仅当a与p互质。一般题目给的p是一个大质数,所以只要a不是p的倍数,就以求乘法逆元。

目前了解到的求法有三种:

1.扩展欧几里得。 a a − 1 ≡ 1 (   m o d     p ) aa^{-1}≡ 1(\bmod \ p) aa11(mod p),可以转换为 a a − 1 + p y = 1 aa^{-1} + py = 1 aa1+py=1,即是扩展欧几里得所能解的ax + by = gcd(a, b)。最常用的解法。(p可以不是质数,但a、p必须互质)
int x, y;  
int extgcd(int a, int b, int &x, int &y)  
{  
    if (b == 0){  
        x = 1;  
        y = 0;  
        return a;  
    }  
    int gcd = exgcd(b, a % b, x, y);  
    int tmp = x;  
    x = y;  
    y = tmp - (a/b) * y;  
    return gcd;  
}  
/* 
求解ax+by=gcd(a,b),亦即ax≡1(mod b)。函数返回值是a,b的最大公约数,而x即a的逆元。 
注意a, b不能写反了。 
*/  
2.由费马小定理(p必须为质数)

p p p 为素数, gcd ⁡ ( a , p ) = 1 \gcd(a, p) = 1 gcd(a,p)=1 ,则 a p − 1 ≡ 1 ( m o d p ) a^{p - 1} \equiv 1 \pmod{p} ap11(modp)

稍作变形即是 a a p − 2 ≡ 1 (   m o d     p ) aa^{p-2}≡ 1(\bmod \ p) aap21(mod p),是不是发现了, a p − 2 a^{p-2} ap2即是a的逆元,这个可以用快速幂来求。

当模p不是素数的时候需要用到欧拉定理
a ϕ ( p ) ≡ 1 (   m o d     p ) a^{\phi(p)}≡1 (\bmod \ p) aϕ(p)1(mod p)
a ∗ a ϕ ( p ) − 1 ≡ 1 (   m o d     p ) a*a^{\phi(p)-1}≡1 (\bmod \ p) aaϕ(p)11(mod p)
a − 1 ≡ a ϕ ( p ) − 1 (   m o d     p ) a^{-1}≡a^{\phi(p)-1} (\bmod \ p) a1aϕ(p)1(mod p)
所以 a ϕ ( m ) − 1 a^{\phi(m)−1} aϕ(m)1为a的逆元
时间复杂度 O ( n ) O(\sqrt n) O(n )即求出单个欧拉函数的值
(当p为素数的时候 ϕ ( p ) = p − 1 \phi(p)=p-1 ϕ(p)=p1,则 ϕ ( p ) − 1 = p − 2 \phi(p)-1=p-2 ϕ(p)1=p2可以看出欧拉定理是费马小定理的推广)
PS:很少会用欧拉定理求逆元

3.逆元打表

有时会遇到这样一种问题,在模质数P下,求1~n的逆元 n< P(这里为奇质数)。可以O(n)求出所有逆元,有一个递推式如下
i n v [ i ] = ( P − P / i ) ∗ i n v [ P % i ] % P inv[i]=(P-P/i)*inv[P\%i]\%P inv[i]=(PP/i)inv[P%i]%P
它的推导过程如下,设 P = t ∗ i + k ( k < i , 1 < i < p ) P=t*i+k(k<i,1<i<p) P=ti+k(k<i,1<i<p),则 t = P / i , k = P % i t=P/i,k=P\%i t=P/i,k=P%i ,那么
⇒ t ∗ i + k ≡ 0 ( m o d P ) ⇒ k ≡ − t ∗ i ( m o d P ) \Rightarrow t*i+k\equiv 0\pmod P\\ \Rightarrow k\equiv -t*i \pmod P ti+k0(modP)kti(modP)
对上式两边同时除 i ∗ k i*k ik,进一步得到
i n v [ i ] ≡ − t ∗ i n v [ k ] ( m o d P ) inv[i] \equiv -t*inv[k] \pmod P inv[i]tinv[k](modP)
再把和替换掉,最终得到
i n v [ i ] = ( P − P / i ) ∗ i n v [ P % i ] % P inv[i]=(P-P/i)*inv[P\%i]\%P inv[i]=(PP/i)inv[P%i]%P
初始化 inv[1]=1,这样就可以通过递推法求出 1~n 模奇素数 P 的所有逆元了。
另外有个结论 1 … P 1\ldots P 1P P P P 的所有逆元值对应 1 … P 1 \ldots P 1P 中所有的数,比如 P=7 ,那么 1 … P 1 \ldots P 1P 对应的逆元是 1 , 4 , 5 , 2 , 3 , 6 1,4 ,5 ,2 ,3 ,6 1,4,5,2,3,6

typedef  long long ll;  
const int N = 1e5 + 5;  
int inv[N];  
   
void inverse(int n, int p) {  
    inv[1] = 1;  
    for (int i=2; i<=n; ++i) {  
        inv[i] = (ll) (p - p / i) * inv[p%i] % p;  
    }  
}  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值