乘法逆元(inverse element)及四大相关求法详解(含证明)

本文深入探讨了乘法逆元的概念,包括极简与详细定义,并通过证明阐述了其重要性。文章详细介绍了四种求解逆元的方法:费马小定理、扩展欧几里得算法、线性递推和欧拉定理,并提供了每种方法的证明和代码实现。此外,还讨论了阶乘逆元在排列组合计算中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

乘法逆元及四大相关求法详解(含证明)

知识的补缺是老生常谈的一大问题,随着自身学习进程的推进,越发觉着逆元知识的重要,故此我站在网上各路大牛的肩膀上,对此知识进行一定程度上的系统梳理。如有不足之处,还请大家指出,大家共同进步,互利共赢 !!

开胃菜

先呈上菜:

在这里插入图片描述

很明显,上述式子只有一条不成立,即 ( a / b ) % m,但有些情况下,又需要进行有模运算的除法。由于式子不成立,当 a 过大或者 b 过大时,极易导致计算过程丢失精度,造成结果误差。因此,为了避免这一遭,逆元就应运而生了。

1. 定义及理解


1.1 乘法逆元的定义


1.1.1 极简定义

​ 在 模m 有意义的条件下, 若 ax ≡ 1 ( mod m ), 则称 a 关于 1 模 m的乘法逆元为 x


1.1.2 详细定义

​ 若整数 a,m 互质,并且对于任意的整数 b,如果满足 a | b ( a 能整除 b ),则存在一个整数 x,使得 b/a ≡ bx ( mod m ) ,则称 x 为 a 模 m 的乘法逆元,记为 a − 1 a^{−1} a1( mod m ) 或者 inv( a )


1.1.3 理解及其相关证明

根据定义:模 m 意义下, a 如果有逆元 x,那么除以 a 相当于乘以 x

b / x1 = b * x1^-1 // 即 b / a = b * a^-1 ,基础乘除转换
inv[x1] ≡ x1^-1 ( mod m) // inv[x1] 即为 x1 在模 m 情况下的逆元
b / x1 ≡ b * inv[x1] ( mod m ) // 结论

b / x1 ≡ b * inv[x1] ( mod m ) 等式成立证明:( inv[ x1 ] = x , 即 x1 的逆元为 x)

假设: 
      b1 / x1 mod m = n (式子一)
(式子一两边同时乘上 x1)
      b1 mod m = n * x1 mod m (式子二)
(简化式子二)
      b1 ≡ n * x1 ( mod m ) (式子三)
(式子三两边同时乘上 x, x 为 1 / x1, 即假设 x 为 x1 的逆元)
(根据定义式) 
      x * x1 ≡ 1 ( mod m ) (式子四 ,因为 x 是 x1 的逆元,所以得出这个式子)
      b1 * x ≡ n * x1 * x ( mod m ) (式子三等式两边乘以 x -> 式子五)
(式子四带入式子五,有)
      b1 * x ≡ n * 1 ( mod m ) (式子六)
(式子六化简)
      b1 * x ≡ n ( mod m ) (式子七)
(与式子七变形)
      b1 * x mod m = n mod m (式子七)
(式子一带入式子七)
      b1 * x mod m =  b1 / x1 mod m mod m (式子八)
(等式右边模了一次 m 之后,值肯定比 m 小,因此第二次模 m 无意义,式子八简化)
      b1 * x mod m =  b1 / x1 mod m (结论) (x 是 x1 的逆元,式子三定义的)
(证毕)

注意 \color{orange}注意 注意

① 当且仅当 a 与 m 互质时,a 关于 1 模 m 的 乘法逆元 有解。特别地,当模数 m 为质数时, a m − 2 a^{m-2} am2 即为 a 的乘法逆元。若不互质,则无解。

② 若 m 为素数,则从 1 到 m-1 的任意数都与 m 互质,即在 1 到 m-1 之间都恰好有一个关于 1 模 m 的乘法逆元。


Q : \color{Red}Q: Q: 为什么当 a 与 m 互质时,a 关于 1 模 m 的 乘法逆元 才有解 ???

首先介绍一下 裴蜀定理

裴蜀定理 \color{orange}裴蜀定理 裴蜀定理
① 若 a, b 是整数,且 gcd(a , b) = d,那么对于任意的整数 x , y。ax+by 都一定是 d 的倍数,特别地,一定存在整数x,y,使 ax+by = d成立。

② 推论:a ,b 互质的充分必要条件是存在整数 x , y 使得 ax+by = 1 。

我们可以知道

​ a ⋅ x ≡ 1( mod m)

⇔ a ⋅ x= 1−my

⇔ ax + my= 1 (  1  ) (\ 1\ )  1 

裴蜀定理告诉我们,方程(1)当且仅当 gcd( a ,m) = 1时有解。也就是说,当且仅当 a 与 模数m 互质时,存在 a 的乘法逆元。因此 大部分 有理数取模问题给定的模数都是质数,这样能够在 a mod m ≠ 0 的情况下保证存在 a 的逆元。


Q : \color{Red}Q: Q: 为什么当模数 m 为质数时, a m − 2 a^{m-2} am2 即为 a 的乘法逆元 ???

由费马小定理可知:

当 m为质数时, a m − 1 a^{m−1} am1 ≡ 1 ( mod m )

​ ⇒ a * a m − 2 a^{m−2} am2 ≡ 1 ( mod m )

则由逆元定义可知,此时 a m − 2 a^{m−2} am2为 a 的乘法逆元



2. 逆元的四大求解法


2.1 费马小定理求逆元


2.1.1 何为费马小定理

费马小定理是数论中一个定理:

假如 a 是 一个整数,m 是一个质数,那么

a m a^{m} am ≡ a ( mod m )

如果 m 是一个质数,而整数 a 不是 m 的倍数,那么

a m − 1 a^{m−1} am1 ≡ 1 ( mod m )


2.1.2 证明费马小定理

下面的证明,使用模运算,最初是由 James Ivory 在1806年发现的,后来被 Dirichlet 在1828年重新发现。

我们首先考虑整数a,2a,3a,…( p - 1 )a。这些数都不等于p对其他数的模,也不等于0。

如果这样,那么有:r × a ≡ s × a ( mod p ),1 ≤ r < s ≤ p - 1,那么,两边消去a将得到

r ≡ s ( mod p ),这是不可能的,因为 r 和 s 都在 1 和 p - 1 之间。

因此,前一组整数必须同余模 p 到1,2,…p - 1。

把这些同余相乘,你会发现:a × 2a × 3a × … × (p - 1) × a ≡ 1 × 2 × 3 × … × (p - 1) ( mod p)意味着a × (p - 1)! ≡ (p - 1)!(mod p)。

从这个表达式的两边消去(p - 1)!,我们便得到: a p − 1 a^{p-1} ap1 ≡ 1 ( mod p )。


2.1.3 代码板子

首先翻出我们之前准备好的结论:
                 b / x1 mod m =  b * x mod m (x 是 x1 在模 m 下的逆元) (式子一)
逆元定义:
                 x1 * x ≡ 1 ( mod m ) (式子二)
我们把费马小定理的结论带入式子二,有
                 x1 * x = x1^(p-1) (式子三)    
故此
                 x = x1^(p-2) (结论) ( 即 x1的 逆元 x 为 x1^(p-2) )
/* 快速幂· 求 a^k % m */
/* 求逆元 即为 quick_power( a , m-2 , m ) */

int quick_power(int a,int k,int m)
{
    int res=1;
    
    while(k)
    {
        if(k&1) res= res*a % m;
        a= a*a % m;
        k>>=1;
    }
    
  return res;
}

费马小定理局限性 \color{Green}费马小定理局限性 费马小定理局限性

必须满足 m 要为质数 的前提条件 ,才可求逆元



2.2 扩展欧几里得求逆元


2.2.1 何为欧几里得算法

欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。

公式 :gcd( a,b ) = gcd( b,a mod b )


2.2.2 证明欧几里得算法

在这里插入图片描述

2.2.3 扩展欧几里得算法

由名字可知这是建立在欧几里得算法上的一种算法,定义如下:

​ 给一个线性方程 ax + by = m,给出 a,b,m 求解出相应的 x 和 y 。

注意 \color{orange}注意 注意

首先,只有 m % gcd( a,b) ==0 ,即 当且仅当 m 是 a,b 最大公约数的倍数时,该线性方程才有解。

当 m 为1 时,由裴蜀定理推论可知,只有当 a,b互质才有解。


2.2.4 推导扩展欧几里得算法

证:存在整数对( x,y )使得 ax + by = gcd( a,b )

 证明:
 设 a > b 
       当 b = 0 时,a∗1+b∗0 = gcd( a,b ) = a,此时 x=1,y=0 
      
       当 b !=0 时,    
设 a∗x1 + b∗y1 = gcd( a,b ) 
   b∗x2 + a%b∗y2 = gcd( b,a%b ) 
   
 又由于gcd(a,b)=gcd( b,a%b )

 所以有  a∗x1 + b∗y1=b∗x2 + a%b∗y2 
 又因为  a%b = a − ( a / b )∗b , 
  得到   a∗x1 + b∗y1=a∗y2 + b∗x2 − ( a / b )∗b∗y2 

​      即     x1=y2
​             y1=x2 − (a/b)∗y2 

因此可以递归的定义exgcd,同样b=0时递归结束。返回最大公约数。

2.2.5 代码板子

int exgcd( int a , int b , int &x , int &y )
{
    if( !b ) // 当 b =0 时
    {
        x=1,y=0;
        return a;      
    }
    
    // 当 b!=0 时
    int d=exgcd( b, a%b, x, y );
    int t=x;
    
    x=y;
    y=t-(a/b)*y;
    
    return d;
}

怎么用拓展欧几里得求逆元呢?

把 ax ≡ 1( mod m)称为 a 关于 1 mod m 的乘法逆元。 它的解其实就相当于寻找方程 ax+my=1 的解。根据乘法逆元的性质,只有当 a 与 m 互质,a 关于模 m 的乘法逆元才有解。如果不互质,则无解。那么这个方程就是 a,m 互质的充要条件是方程 ax+my = 1 必有整数解。

注意 \color{orange}注意 注意

我们知道了线性方程 ax + by = m 有整数解的条件,并且根据上述算法,也能求出一组方程的解。但是 这组解很可能包含负数,当我们求逆元时需将其转化为正数,如下

/* 求逆元 a , m */
int Inv_a(int a,int m)
{
    int x,int y;
    int d=exgcd(a,m,x,y);
    
    if(d==1)
    {
        return ( x%m + m )%m; // 保证逆元为正数
    }
    else
       return -1;  // ax+my=1 不成立,即 a ,m  不互质,无解
    
}


2.3 线性递推求逆元


2.3.1 何为线性递推

exgcd和费马小定理只适合用来求单个逆元,求3e6以内所有的逆元在肯定会超时,此时用线性递推求逆元可以保证时间复杂度在O( n )内


2.3.2 推导线性递推

设 t = m / i,k = m % i,有:m = i * t + k
即 i * t + k Ξ 0 ( mod m )
即 k Ξ - i * t ( mod m )
两边同时除以 i * k
有 1 / i Ξ - t / k ( mod m )
将k,t带入
有 inv[ i ] Ξ - m / i * inv[ m % i ] ( mod m )
为防止有负数,有inv[ i ] = ( m - m / i) * inv[ m % i ]) % m

核心inv[ i ] = ( m - m / i ) * inv[ m % i ] % m


2.3.3 代码板子

long long inv[N];

void get_inv( long long m )
{
    inv[1]=1;
    
    for(int i=2;i<=m-1;i++)
        inv[i]=( m-m/i )*inv[ m%i ]%m;
}


2.4 欧拉定理求逆元


2.4.1 何为欧拉定理

若a、m互质,则有 a φ ( m ) a^{φ( m)} aφ(m) ≡ 1 ( mod m ) ,φ( m)称为欧拉函数,表示1~m中与 m互质的个数


2.4.2 证明欧拉定理

欧拉定理证明

把不超过𝑚且与𝑚互质的正整数拿出来构成集合{ x 1 , x 2 , … , x φ ( m ) x_1,x_2,…,x_{φ(m)} x1,x2,,xφ(m)}

设𝑎与𝑚互质且xi也与m互质,则( a x i a_{xi} axi,m )=(m, a x i a_{xi} axi%m) =1

集合{ a x 1 , a x 2 , … , a x φ ( m ) ax_1,ax_2,…,ax_{φ(m)} ax1,ax2,,axφ(m)}在模𝑚意义下与前一集合相等 ( 都是与m互质的集合 )(均为模m意义下模𝑚意义下的缩系)

将集合内所有原数相乘,得到
a x 1 , a x 2 , … , a x φ ( m ) ax_1,ax_2,…,ax_{φ(m)} ax1,ax2,,axφ(m) a φ ( m ) ∏ i ϕ ( m ) x i ≡ ∏ i ϕ ( m ) x i a^{φ(m)}∏^{ϕ(m)}_ixi≡∏^{ϕ(m)}_ixi aφ(m)iϕ(m)xiiϕ(m)xi ( mod m )
因为 xi 与 m 互质,则都有逆元

对上个式子的右边2个式子每个 xi 都乘上逆元
a φ ( m ) a^{φ(m)} aφ(m) ≡ 1 ( mod m )

证毕


2.4.3 推导欧拉函数

欧拉函数 \color{orange}欧拉函数 欧拉函数

ϕ( m ) 为正整数 m 与1,2,⋅⋅⋅,m−1,m互质的个数

设 m = p a 1 p a 2 ⋅ ⋅ ⋅ ⋅ p a k p^{a1}p^{a2}⋅⋅⋅⋅p^{ak} pa1pa2pak

则 ϕ( m ) = ( p 1 − 1 ) p 1 a 1 − 1 × ( p 2 − 1 ) p 2 a 2 − 2 ⋅ ⋅ ⋅ × ( p k − 1 ) p k a k − 1 (p_1−1)p_1^{a1−1}×(p_2−1)p_2^{a2−2}⋅⋅⋅×(p_k−1)p_k^{ak−1} (p11)p1a11×(p21)p2a22×(pk1)pkak1

取自[逆元、欧拉定理 - I_N_V - 博客园 (cnblogs.com)]在这里插入图片描述


2.4.4 代码板子

int phi(int x)
{
    int ans=x;
    for( int i=2 ; i*i<=x ; i++ )// 时间复杂度:O ( √n )
        if(x%i==0)
        {
            ans = ans/i*(i-1); // 由 Φ(m)=m(1- 1 / pi)..得出 
            while(x%i==0) x/=i;// 除干净质因子
        }
    
    if(x>1)
        ans=ans/x*(x-1);// m有一个大于√m 的质数
    
    return ans;
}




3. 阶乘逆元

顾名思义,就是阶层的逆元,即分母,既然这篇文章主要是以逆元为主题,那么顺道提一下,希望有助于排列组合的计算,上板子!!

// 阶乘逆元
typedef long long LL;
const int N=1e6+5;
LL fac[N];        //阶乘
LL inv[N];        //逆元 

// 求阶乘
void get_fac()
{
    fac[0] = inv[0] = 1;
    for (int i = 1 ; i <= 1000000 ; i++)
    {
        fac[i] = fac[i-1] * i % m;
        inv[i] = quick_power(fac[i],m-2,m);        
        //表示i的阶乘的逆元 
    }
}

// 求组合数
inline LL get_C( LL a, LL b ) //   C(a,b) = a!/((a-b)!*b!) % mod
{
    return fac[a] * inv[a-b] % m * inv[b] % m;
}

以上内容尚未完全,随着今后学习的推进,我会继续对其进行补充与完善。另外,大家如果觉得我写的还行的话,还请赠予我一个可爱的赞,你的赞对于我是莫大的支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值