若a * x 1 (mod b), a, b互质,则称x为a的逆元, 逆元也可以写成。
(t/a) mod b = t * x mod b.
求逆元的方法:
1.EXGCD
a * x 1 (mod b) ——> a * x + b * y = 1。用扩展欧几里得求解得到x的值即可。
int exgcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
int k = exgcd(b, a % b, x, y);
h = x;
x = y;
y = h - (a / b) * y;
return k;
}
2.费马小定理
如果p为质数,
a * 1
所以逆元为 。直接快速幂即可。
int KSM(int n, int x){
int ans = 1;
while(x > 0){
if(x % 2) ans = ((ans % p) * (n % p)) % p;
n = ((n % p) * (n % p)) % p;
x /= 2;
}
return ans;
}
3.欧拉定理
把费马小定理中的p-2换成f(p) - 1。
f(p) 是欧拉函数。(在博客欧拉函数里面,大致就是n之前的与n互素的数的个数)
#include
int n, m, p, ans;
int phi(int n){
int res = n;
for (int i = 2; i * i <= n; i++){
if(n % i == 0){
res = res - res / i;
while(n % i == 0) n /= i;
}
}
if(n > 1) res = res - res / n;
return res;
}
int KSM(int n, int x){
int ans = 1;
while(x > 0){
if(x % 2) ans = ((ans % p) * (n % p)) % p;
n = ((n % p) * (n % p)) % p;
x /= 2;
}
return ans;
}
int main(){
scanf("%d%d", &n, &p);
ans = KSM(n, phi(p) - 1);
printf("%d", ans);
return 0;
}
4.递推
首先, 1(mod p)
然后设p = k * i + r, r < i, 1 < i < p,再将这个式子放到mod p 意义下:
k * i + r 0 (mod p)
再两边同乘,得到
k * + 0
-k*
-[p/i] *
所以a[i] = -(p / i) * a[p % i];
void work(int n, int p){
inv[1] = 1;
for (int i = 2; i <= n; i++){
inv[i] = (p - p / i) * inv[p % i] % p;
}
}
即可求出1-n关于p的逆元。(p - p / i)是因为加个p使其为正数。