数学:快速幂、费马小定理、乘法逆元
1. 快速幂、龟速乘、快速乘
- 快速幂:
O(\log b) 求a^b\pmod {m}
const int mod = 1e9 + 7; //模数最好写成常数
int qpow(int a, int b) { //求a^b%mod,其中b>=0,mod>1
int s = 1;
while (b > 0) {
if (b & 1) s = 1ll * s * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return s;
}
- 龟速乘:
O(\log b) 求a\cdot b\pmod m
int qmul(int a, int b) {
int s = 0;
while (b > 0) {
if (b & 1) s = (s + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return s;
}
- 快速乘:用浮点数求
a\cdot b\pmod m
2009国家集训队论文 《论程序底层优化的一些方法与技巧》 骆可强
https://img-blog.csdn.net/20181015235114249?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0N5YW5fcm9zZQ
其他:int128
快速幂例题:https://www.luogu.com.cn/problem/U400677
2. 费马小定理
若
证明:
考虑序列
考虑
所以
所以
3. 乘法逆元
若 3 * 2 % 5 = 1
逆元存在的条件:
求逆元的方法:
(1) 快速幂+费马小定理求逆元(模数是质数)
(2) exgcd求解线性同余方程 (不要求模数m是质数,只要求a与m互质)
解方程
(3) 递推求逆元(模数是质数)(不太好用)
求
推导:记
用这种方法可以递归
// 求1~p-1的逆元
inv[1] = 1;
for (int i = 2; i < p; ++i) //防止负数
inv[i] = (p - p / i) * inv[p % i] % p;
(4) 线性求
相邻两项的逆元有什么关系?
// 求0~n的阶乘
fact[0] = 1;
for (int i = 1; i <= n; ++i)
fact[i] = fact[i - 1] * i % p;
// 费马小定理求n!的逆元
factinv[n] = qpow(fact[n], p - 2);
// 求(n-1)!~0!的逆元
for (int i = n - 1; ~i; --i)
factinv[i] = factinv[i + 1] * (i + 1) % p;
求得