乘法模运算逆元
逆元 (Multiplicative Inverse)
逆元是在特定运算下的"反转"
举几个例子
- 加法
a的加法逆元就是-a, 它们相加为0 - 乘法逆元
a的乘法逆元是1/a, 它们相乘为1 - 矩阵乘法
矩阵的逆元是逆矩阵, 它们相乘为单位矩阵
有人会问了, 为什么它们运算结果并不一样呢? 他们的共性在哪里?
这里的关键在于, 他们的运算结果都是源于运算的"基本性质"和"单位元素"
所谓单位元素就是, 在加法中, 任意元素加0不会改变, 而乘法中, 所有元素乘以1不会改变, 这就是单位元素, 矩阵同理
乘法模运算逆元
很多算法题目中会涉及到乘法模运算的逆元
我举2个例子
- 题目给了100个数的乘积模1e9+7之后的结果, 然后给了后50个数乘积模1e9+7的结果
请问前50个数的乘积模1e9+7是多少? - 组合数学涉及到计算非常大的C(n, m) mod M 的时候
这都是需要"回撤"或"反转"的时候
求逆元算法
- 扩展欧几里得 (exgcd)
- 费马小定理 (需要模数M是素数)
- 欧拉定理
费马小定理
说一下费马小定理
因为它比较简单
费马小定理: 若M是质数,且B、M互质,那么B^(M-1) mod M = 1
所以可以扩展到
A/B mod M
= A/B mod M * 1
= A/B mod M * B^(M-1) mod M
= A*B^(M-2) mod M
于是除法就被转换成了乘法
这里求B的M-2幂次的时候用快速幂, 所以是个O(logn)的算法
计算C(n, m)
首先, 定义一下阶乘为fac(x)
组合数的公式很简单
C(n, m) = fac(n) / (fac(m) * fac(n-m))
那首先我们需要预处理两个数组
fac, inv
前者计算从1到n的阶乘的模M结果(复杂度O(n))
后者计算从1到n的阶乘的模M的逆元(复杂度O(n))
前面讲了单次求逆元复杂度是O(logn), 但是这里整体复杂度为什么不是O(nlogn)呢? 因为这里有个递推关系, 他们彼此之间是有依赖关系的, 并不需要每个数组元素都单独计算一遍
inv[i] * fac[i] == 1 (% MOD)
inv[i] * fac[i] * (i+1) == (i+1) (% MOD)
inv[i] * fac[i+1] == (i+1) (% MOD)
inv[i] = (i+1) / fac[i+1] (% MOD)
我们一开始这俩数组目的是什么? 是不是inv_arr[i] * f_arr[i] == 1 (%MOD)
注意到右边其实就是(i+1) * inv[i+1]
所以只要倒着算就可以递推了
void init() { fac[0]=inv[0]=1; for (long long i = 1; i < maxn; i++) { fac[i] = fac[i - 1] * i % MOD; } inv[maxn-1] = quickpower(fac[maxn-1], MOD - 2); for(int i = maxn-2; i>=0; i--){ inv[i] = inv[i+1] * (i+1) % MOD; } }
所以C(n, m)是不是可以张口就来?
C(n, m) = fac[n] * inv[n-m] % MOD * inv[n] % MOD;
除法转换为乘法就可以了
完整小case
计算 fac(1到99) / fac(5到99) = 24
#include <bits/stdc++.h> using namespace std; const int MOD = 1e9 + 7; long long pow(long long a, int b) { long long ret = 1; while (b) { if (b & 1) { ret *= a; ret %= MOD; } a *= a; a %= MOD; b >>= 1; } cout << "ret " << ret << endl; return ret; } int main() { long long a = 1; for (int i = 1; i < 100; i++) { a = a * i % MOD; } cout << a << endl; long long b = 1; for (int i = 5; i < 100; i++) { b = b * i % MOD; } cout << b << endl; // A/B MOD M = A * B^(M-2) MOD M long long c = a * pow(b, MOD - 2) % MOD; cout << c << endl; return 0; } // 费马小定理: 若M是质数, 且B, M互质, 那么 B^(M-1) MOD M = 1
posted on 2023-11-21 20:23 tianlonghuangwu 阅读(61) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现