求逆元

若a * x \equiv 1 (mod b), a, b互质,则称x为a的逆元, 逆元也可以写成a^{-1}

(t/a) mod b = t * x mod b.

求逆元的方法:

1.EXGCD

    a *  x \equiv 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^{p - 1} \equiv 1(mod b)

   a * a^{p - 2} \equiv 1

   所以逆元为 a^{p - 2} 。直接快速幂即可。

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^{-1}\equiv1(mod p)

然后设p = k * i + r, r < i, 1 < i < p,再将这个式子放到mod p 意义下: 

k * i + r \equiv 0 (mod p)

再两边同乘i^{-1}r^{-1}得到

k * r^{-1} + i^{-1}\equiv0

 i^{-1}\equiv -k*r^{-1}

 i^{-1}\equiv -[p/i] * (p mod i)^{-1}

所以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使其为正数。

你可能感兴趣的:(数论)