目录
1.费马小定理 (Fermat's Little Theorem)
一、快速幂
1.递归实现
递归实现的基本思想是利用分治法,将问题分解为更小的子问题。对于一个数 x
的 n
次幂,可以根据 n
的奇偶性进行不同的处理:
- 如果
n
是偶数,x^n = (x^(n/2))^2
- 如果
n
是奇数,x^n = x * x^(n-1)
long double QuickPow(double x, int n) {
if (n == 0) return 1; // 基本情况
if (n < 0) return 1 / QuickPow(x, -n); // 处理负指数
if (n & 1) { // 使用位运算检查奇数
return x * QuickPow(x, n - 1); // 奇数情况
} else {
double half = quickPowRecursive(x, n >> 1); // 使用位运算右移
return half * half; // 偶数情况
}
}
2. 迭代实现
迭代实现则使用循环来逐步计算结果。通过不断将 n
除以 2 来减少问题规模,同时维护一个结果变量:
- 初始化结果为 1
- 当
n
大于 0 时:- 如果
n
是奇数,将当前的x
乘入结果 - 将
x
自身平方(即x = x * x
) - 将
n
除以 2
- 如果
long double QuickPow(double x, int n) {
double result = 1;
long long exp = n; // 使用 long long 处理负数
if (exp < 0) {
x = 1 / x; // 处理负指数
exp = -exp;
}
while (exp > 0) {
if (exp & 1) result *= x; // 使用位运算检查奇数
x *= x; // 自身平方
exp >>= 1; // 使用位运算右移
}
return result;
}
二、模意义下乘法运算的逆元
1.费马小定理 (Fermat's Little Theorem)
如果 p 是素数,且 a 是不被 p 整除的整数,则:a ^ (p - 1) = 1 (mod p)
由此可以推导出: a ^ (p - 2) = a ^ -1(mod p)
这意味着 a ^ -1 可以通过快速幂计算 a ^ (p - 2) 来得到。
long double inv(double x) {
return QuickPow(x, p - 2); // p通常为题目所给取模常量,如1e9 + 7
}
2.扩展欧几里得法
// 扩展欧几里得算法
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 gcd = exGCD(b, a % b, x1, y1);
x = y1;
y = x1 - (a / b) * y1;
return gcd;
}
// 求模逆元
long long modInverse(long long a, long long m) {
long long x, y;
long long gcd = exGCD(a, m, x, y);
if (gcd != 1) {
cout << "Inverse doesn't exist" << endl;
return -1; // 逆元不存在
} else {
// x 可能是负数,确保返回正值
return (x % m + m) % m;
}
}