数论专题-逆元

本篇博客是【数论专题】系列的第 \(8\) 篇,希望大家多多支持。

\(a\times x\equiv 1\pmod p\),并且 \(a, p\) 互质,则称 \(a\)\(p\) 的乘法逆元为 \(x\),记作 \(a^{-1}\)

费马小定理求逆元

注意,当模数 \(p\) 是质数且 \(a\ne 0\) 时,才可使用费马小定理求逆元。

根据费马小定理:

\[a^{p - 1}\equiv 1\pmod p \]

因此:

\[a\times a^{p - 2}\equiv 1\pmod p\\ \]

很明显,此时 \(a^{p - 2}\) 即为 \(a^{-1}\)

使用快速幂求出 \(a^{p - 2}\bmod\ p\) 即可,时间复杂度 \(O(\log p)\)

int qpow(int a, int b, int mod)
{
	int ans = 1;
	while(b)
	{
		if(b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}//快速幂模板
int get_inv(int a, int p)
{
	return qpow(a, p - 2, p);//求出逆元
}

扩展欧几里得算法求逆元

\(a\times x\equiv 1 \pmod p\) 可以转化为求解 \(a\times x + p\times y = \gcd(a, p) = 1\)(当 \(\gcd(a, p) = 1\) 才有解,这也符合逆元的定义)。那么,可以使用扩展欧几里得算法求解。

但是,求解出来的 \(x\) 可能是负数,需要通过累加 \(p\) 来处理一下。

void exgcd(int a, int b)//扩展欧几里得算法模板
{
	if(b == 0)
	{
		x = 1, y = 0;
		return;
	}
	exgcd(b, a % b);
	int tmp = x;
	x = y;
	y = tmp - a / b * y;
}
int get_inv(int a, int p)
{
	exgcd(a, p);
	return (x % p + p) % p;//使 x 变为最小正整数解
}

递推求逆元

\(p = k\times i + r, r < i, 1 < i < p\),然后把这个式子放在 \(\bmod\ p\) 意义下可以得到:

\[k\times i + r \equiv 0\pmod p \]

将两边同时乘上 \(i^{-1}\)\(r^{-1}\) 可以得到:

\[\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k\times r^{-1} + i^{-1}\equiv 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \pmod p\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i^{-1}\equiv -k\times r ^ {-1}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \pmod p\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i^{-1}\equiv - \lfloor \frac{p}{i} \rfloor \times (p\bmod\ i)^{-1}\pmod p \]

通过这个式子即可从前面的数推出当前数的逆元。

void get_inv(int n, int p)
{
	inv[1] = 1;//初始值
	for(int i = 2;i <= n;i ++) inv[i] = (p - p / i) * inv[p % i] % p;//递推式
}
posted @ 2025-08-17 09:08  Loyal_Soldier  阅读(24)  评论(0)    收藏  举报