逆元小结

乘法逆元小结

乘法逆元:在模意义下 乘法和加法都是合法的,但除法并不合法,为了解决除法的问题,引进了乘法逆元 inv(a),记作 a-1  ,即像满足 a*inv(a) ≡ 1 (mod p)这样的 a 的倒数的数 inv(a) 的存在。

 

处理逆元的几种方法:

1、暴力求解

复杂度:O( p ) p 为 模。

假设要求 x 在 mod p 情况下的逆元,暴力枚举 p-1 个数,满足条件:x * num ≡ 1 (mod p);

 

2、费马小定理 && 欧拉定理

复杂度:O(log2N)

费马小定理:a(p-1) ≡ 1 (mod p) 【前提 p为质数】

可得 inv(a) = a(p-2)

欧拉定理:aphi( p ) ≡ 1 (mod p) 【前提 p不为质数】当然 p 不为质数的情况下不一定每一个数都存在逆元。

可得 inv(a) = aphi(p)-1

即根据 p 的情况,选用快速幂求解。

 

 1 LL pow_mod(LL a, LL b, LL p){            //a的b次方结果模p 
 2     LL ret = 1;
 3     while(b){
 4         if(b & 1) ret = (ret * a) % p;
 5         a = (a * a) % p;
 6         b >>= 1;
 7     }
 8     return ret;
 9 }
10 LL Fermat(LL a, LL p){                //费马求a关于p的逆元 
11         return pow_mod(a, p-2, p);
12 }

 

 3、拓展欧几里得(by 《挑战》)

由于方程 a * inv(a) ≡ 1 (mod p) 等价于存在一个整数 k 使得 a*inv(a) = 1+k*p;

即问题转换成 求解满足 a* inv(a) - k*p = 1 的 inv(a) 的问题,可以运用 extgcd (拓展欧几里得)求解。

同时!!! 如果 gcd(a, p) != 1 则逆元不存在。

 

 1 int exgcd(int a,int b,int &x,int &y) 
 2 {  
 3     if(b==0)
 4     {
 5         x=1;y=0;
 6         return a;  
 7     }
 8     int d=exgcd(b,a%b,y,x);
 9     y=y-a/b*x;
10     return d;
11 }
12 int mod_inverse(int a,int mod)//求a关于mod的逆元
13 {
14     int x,y;
15     exgcd(a,mod,x,y);
16     return (x%mod+mod)%mod;
17 } 

 

4、万能公式法

以上几种方法都存在局限性,那么怎么办呢?

在 a | b 的情况下: a/b mod p = a mod (bp) / b 

 

5、神奇线性大法预处理 1~N 的逆元

参考:http://blog.miskcoo.com/2014/09/linear-find-all-invert

模板:

inv[1] = 1;

inv [ i ] = (mod - mod/i)*inv[ mod%i ] %mod; 

 

6、巧妙预处理阶乘逆元

在HDU多校一道莫队的题看到的技巧,当时就ORZ.....

http://acm.hdu.edu.cn/showproblem.php?pid=6333

首先快速幂求出 (maxn-1) ! 在mod的意义下的逆元;

逆推: inv[ i ] = (inv[ i + 1]*(i+1))%mod;

 1 void init()
 2 {
 3     rev2 = q_pow(2, MOD-2);                     // 2的逆元
 4     fac[0] = fac[1] = 1;
 5     for(LL i = 2; i < MAXN; i++){              //预处理阶乘
 6         fac[i] = fac[i-1]*i%MOD;
 7     }
 8 
 9     inv[MAXN-1] = q_pow(fac[MAXN-1], MOD-2);    //逆推预处理阶乘的逆元
10     for(int i = MAXN-2; i >= 0; i--){
11         inv[i] = inv[i+1]*(i+1)%MOD;
12     }
13 }

 

1 void Init()                                 //预处理排列数和逆元
2 {
3     fac[0] = Inv[0] = fac[1] = Inv[1] = 1;
4     for(int i = 2; i < MAXN; i++) fac[i] = fac[i-1]*i%mod;
5     for(int i = 2; i < MAXN; i++) Inv[i] = (mod-mod/i)*Inv[mod%i]%mod;
6     for(int i = 2; i < MAXN; i++) Inv[i] = Inv[i]*Inv[i-1]%mod;
7 }

 

### 使用费马小定理计算模逆元 #### 方法概述 当给定两个正整数 \( b \) 和 \( m \),其中 \( b \) 和 \( m \) 互质,且 \( m \) 是一个素数时,可以通过费马小定理来高效地计算 \( b \) 关于模 \( m \) 的乘法逆元。根据费马小定理[^2],\( b^{m-1} \equiv 1 \pmod{m} \) 成立。因此,我们可以得出: \[ b \cdot b^{m-2} \equiv 1 \pmod{m}. \] 这意味着 \( b^{m-2} \mod m \) 即为 \( b \) 对模 \( m \) 的乘法逆元。 --- #### 实现过程 以下是基于快速幂算法的 Python 实现代码,用于计算 \( b \) 关于模 \( m \) 的乘法逆元: ```python def fast_pow(base, exp, mod): result = 1 base %= mod # 确保基础取模 while exp > 0: if exp & 1: # 如果指数当前位为1 result = (result * base) % mod base = (base * base) % mod # 幂平方 exp >>= 1 # 右移一位 return result def modular_inverse(b, m): """ 计算 b 关于模 m 的乘法逆元。 :param b: 基础值 :param m: 模数(需为素数) :return: 返回 b 的乘法逆元 """ if gcd(b, m) != 1: # 验证 b 和 m 是否互质 raise ValueError("b 和 m 不互质,无法找到乘法逆元") return fast_pow(b, m - 2, m) from math import gcd # 测试用例 if __name__ == "__main__": b = 7 m = 13 inverse = modular_inverse(b, m) print(f"{b} 关于模 {m} 的乘法逆元是: {inverse}") ``` 上述代码中,`fast_pow` 函数实现了快速幂运算,而 `modular_inverse` 函数利用费马小定理计算乘法逆元。注意,在调用前应验证 \( b \) 和 \( m \) 是否互质;如果不互质,则不存在乘法逆元。 --- #### 数学解释 通过费马小定理可知,若 \( b \) 和 \( m \) 互质且 \( m \) 为素数,则有: \[ b^{m-1} \equiv 1 \pmod{m}, \] 将其改写为: \[ b \cdot b^{m-2} \equiv 1 \pmod{m}. \] 由此可得 \( b^{m-2} \mod m \) 即为所求的乘法逆元。 --- #### 时间复杂度分析 由于采用了快速幂算法,时间复杂度为 \( O(\log(m)) \)[^4],这使其非常适用于大规模数据处理场景。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值