模逆元计算方法详解:扩展欧几里得算法与费马小定理

1. 模逆元简介

在模运算中,对于整数 a 和模数 M,如果存在整数 x 使得 a × x ≡ 1 (mod M),则称 xa 在模 M 下的逆元,记作 a⁻¹inv(a)。模逆元在密码学、组合数学和算法竞赛中有着广泛应用。

2. 方法一:扩展欧几里得算法(通用方法)

扩展欧几里得算法适用于 Ma 互质(即 gcd(a, M) = 1)的情况。该算法不仅能求出最大公约数,还能求出贝祖等式 ax + by = gcd(a, b) 的一组整数解。

2.1 算法实现

以下是扩展欧几里得算法的 C++ 实现:

cpp 复制代码
// 扩展欧几里得算法:求 ax + by = gcd(a,b) 的解
long long exgcd(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long x1, y1;
    long long d = exgcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - (a / b) * y1;
    return d;
}

// 求 a 在模 M 下的逆元
long long mod_inv(long long a, long long M) {
    long long x, y;
    long long d = exgcd(a, M, x, y);
    if (d != 1) return -1;  // 不存在逆元
    return (x % M + M) % M;  // 保证结果为正
}



//简洁点的
//long long inv_exgcd(long long a, long long b){  //	long long b=MOD;
//	int u=1, v=0;
//	while(b) {
//		long long t=a/b;
//		a-=t*b;
//		swap(a,b);
//		u-=t*v;
//		swap(u,v);
//	}
//	return (u%MOD+MOD)%MOD;
//} 

2.2 算法原理

gcd(a, M) = 1 时,扩展欧几里得算法求出的 x 满足 ax + My = 1。对等式两边取模 M,得到 ax ≡ 1 (mod M),因此 x 就是 a 在模 M 下的逆元。

2.3 示例

求 2 在模 7 下的逆元:

text 复制代码
2 × 4 = 8 ≡ 1 (mod 7)
所以 2⁻¹ = 4

使用上述代码计算:mod_inv(2, 7) 返回 4。

3. 方法二:费马小定理(适用于质数模数)

当模数 M 是质数时,根据费马小定理:

text 复制代码
a^(M-1) ≡ 1 (mod M)

因此:

text 复制代码
a⁻¹ = a^(M-2) mod M

3.1 快速幂实现

以下是使用快速幂计算模逆元的 C++ 实现:

cpp 复制代码
long long mod_pow(long long a, long long b, long long mod) {
    long long res = 1;
    while (b > 0) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

// 求 a 在质数模 M 下的逆元
long long mod_inv_prime(long long a, long long M) {
    return mod_pow(a, M - 2, M);
}

3.2 时间复杂度

快速幂的时间复杂度为 O(log M),当 M 很大时(如 10⁹+7),这种方法比扩展欧几里得算法稍慢,但代码更简洁。

4. 方法对比与选择建议

方法 适用条件 时间复杂度 优点 缺点
扩展欧几里得 gcd(a, M) = 1 O(log min(a, M)) 通用性强,可判断逆元是否存在 代码稍复杂
费马小定理 M 为质数 O(log M) 代码简洁,易于实现 仅适用于质数模数

5. 实际应用场景

  • 组合数取模 :计算 C(n, k) mod p(p 为质数)时,需要用到阶乘的逆元。
  • 线性同余方程 :求解 ax ≡ b (mod M) 时,若 gcd(a, M) = 1,则 x ≡ b × a⁻¹ (mod M)
  • 密码学:RSA 算法中私钥的计算涉及模逆元。

6. 注意事项

  1. 使用扩展欧几里得算法时,务必检查 gcd(a, M) = 1,否则逆元不存在。
  2. 费马小定理方法仅当 M 为质数时成立,使用时需确保模数是质数。
  3. 计算结果可能为负数,需要通过 (x % M + M) % M 转换为正数。
  4. 对于大数运算,注意使用 long long 类型,避免溢出。

7.完整模板代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const long long MOD = 998244353;

// 方法1:快速幂求逆元(模数为质数)
long long inv_fermat(long long a) {
    long long res = 1, base = a, exp = MOD - 2;
    while (exp > 0) {
        if (exp & 1) res = res * base % MOD;
        base = base * base % MOD;
        exp >>= 1;
    }
    return res;
}

// 方法2:扩展欧几里得求逆元(通用)
long long inv_exgcd(long long a) {
    long long b = MOD, u = 1, v = 0;
    while (b) {
        long long t = a / b;
        a -= t * b; swap(a, b);
        u -= t * v; swap(u, v);
    }
    return (u % MOD + MOD) % MOD;
}

int main() {
    // 计算 15/2
    long long inv2 = inv_fermat(2);
    cout << 15 * inv2 % MOD << endl;  // 499122184
    
    // 计算 5/3
    long long inv3 = inv_fermat(3);
    cout << 5 * inv3 % MOD << endl;
    
    return 0;
}
相关推荐
@Mike@1 小时前
06-数据库学习笔记(存储模型与数据压缩)
数据库·笔记·学习
脚踏实地皮皮晨2 小时前
002002002_DepandencyObject类2
开发语言·windows·算法·c#·visual studio
我的xiaodoujiao2 小时前
快速学习Python基础知识详细图文教程14--模块
开发语言·python·学习·测试工具
wdfk_prog2 小时前
嵌入式面试真题学习笔记系列
笔记·学习·面试
懿路向前2 小时前
【HarmonyOS学习笔记】2026-07-30 | 小艺开放平台智能体接入实战
笔记·学习·harmonyos
吃好睡好便好3 小时前
MATLAB中图像的线性变换
开发语言·图像处理·学习·计算机视觉·matlab
YUS云生3 小时前
大模型学习·第41天:LangChain进阶——提示词模板与Chain链式调用
学习·langchain·c#
boppu3 小时前
酒店毛巾浴巾洗涤后手感评判标准
学习
冻柠檬飞冰走茶3 小时前
PTA基础编程题目集 7-27 冒泡法排序(C语言实现)
c语言·开发语言·数据结构·算法