乘法模运算逆元
逆元 (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 阅读(116) 评论(0) 收藏 举报
浙公网安备 33010602011771号