[学习笔记]乘法逆元

逆元是什么以及为什么要使用逆元

逆元的作用:在模意义下做乘法的逆运算。

在实数运算中,除以一个数,等于乘上这个数的倒数。而现在在模意义下,逆元就充当了“倒数”的角色,模意义下乘上逆元就相当于除以了一个数。

逆元定义:如果一个线性同余方程 a x ≡ 1 ( m o d b ) ax \equiv 1 \pmod b ax1(modb),则 x x x 称为 a   m o d   b a \bmod b amodb 的逆元,记作 a − 1 a^{-1} a1。所以求逆元实际上就是求如下方程的解:
a x ≡ 1 ( m o d p ) ax \equiv 1 \pmod p ax1(modp)

费马小定理求逆元

费马小定理

p p p 为素数,且 gcd ⁡ ( a , p ) = 1 \gcd(a, p) = 1 gcd(a,p)=1,即 a , p a, p a,p 互质,那么 a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1 \pmod p ap11(modp)


如何用于求逆元

p p p 是质数时,

∵ a p − 1 ≡ 1 ( m o d p ) \because a^{p-1} \equiv 1 \pmod p ap11(modp)

∴ a ⋅ a p − 2 ≡ 1 ( m o d p ) \therefore a \cdot a^{p-2} \equiv 1 \pmod p aap21(modp)

∴ x = a p − 2   m o d   p \therefore x = a^{p-2} \bmod p x=ap2modp

用个快速幂就结束了。

注意限制条件: p p p 必须是质数。

但是大多数情况下OI题目中的模数都是质数,所以这一方法很常用。

时间复杂度 O ( log ⁡ p ) O(\log p) O(logp)

欧拉定理求逆元

例题:NOIP提高组2012 同余方程

欧拉函数

欧拉函数 φ ( x ) \varphi(x) φ(x) 的定义:小于等于 x x x 的数中与 x x x 互质的数的个数。

如何求欧拉函数:
φ ( x ) = ( ∏ i = 1 k p i − 1 p i ) x \varphi(x) = (\prod_{i=1}^k \dfrac{p_i-1}{p_i}) x φ(x)=(i=1kpipi1)x

其中 k k k x x x 中的质因子个数, p i p_i pi x x x 的一个质因子。注意,这里忽略质因数分解中的次数,如
20 = 2 2 × 5 20 = 2^2 \times 5 20=22×5

但是我们计算时只考虑 2 2 2 5 5 5 这两个质因子。


欧拉定理

gcd ⁡ ( a , p ) = 1 \gcd(a, p) = 1 gcd(a,p)=1,那么 a φ ( p ) ≡ 1 ( m o d p ) a^{\varphi(p)} \equiv 1 \pmod p aφ(p)1(modp)


如何用于求逆元

∵ a φ ( p ) ≡ 1 ( m o d p ) \because a^{\varphi(p)} \equiv 1 \pmod p aφ(p)1(modp)

∴ a ⋅ a φ ( p ) − 1 ≡ 1 ( m o d p ) \therefore a \cdot a^{\varphi(p) - 1} \equiv 1 \pmod p aaφ(p)11(modp)

∴ x = a φ ( p ) − 1   m o d   p \therefore x = a^{\varphi(p)-1} \bmod p x=aφ(p)1modp

质因数分解求 φ ( p ) \varphi(p) φ(p) 加上一个快速幂即可。

最坏时间复杂度 O ( p + log ⁡ p ) O(\sqrt p + \log p) O(p +logp)


和费马小定理的关系

有没有发现二者长得很像?
其实费马小定理是欧拉定理的一种特殊情况:
p p p 为质数时,易得 φ ( p ) = p − 1 \varphi(p) = p - 1 φ(p)=p1,此时欧拉定理就成了费马小定理。


例题代码

#include<iostream>
using namespace std;
long long a, b;

long long phi(long long x)
{
	long long res = x;
	for(long long i = 2; i * i <= x; i++)
		if(x % i == 0)
		{
			res = res / i * (i - 1);
			while(x % i == 0)
				x /= i;
		}
	if(x > 1)
		res = res / x * (x - 1);
	return res;
}

long long qpow(long long a, long long b, long long c)
{
	long long res = 1;
	while(b)
	{
		if(b & 1)
			res = res * a % c;
		b >>= 1;
		a = a * a % c;
	}
	return res;
}

int main()
{
	cin >> a >> b;
	cout << qpow(a, phi(b) - 1, b) << endl;
	return 0;
}

扩展欧几里得算法求逆元

例题:NOIP提高组2012 同余方程

裴蜀定理

对于任意整数 a , b a,b a,b,若 a , b a,b a,b 不全为 0 0 0,则存在整数 x , y x,y x,y,满足 a x + b y = gcd ⁡ ( a , b ) ax + by = \gcd(a,b) ax+by=gcd(a,b)

扩展欧几里得算法(简称扩欧,英文名称 exgcd)就是用来求一组满足条件的 x , y x,y x,y 的。


扩展欧几里得算法

b = 0 b=0 b=0 时,有 a x = gcd ⁡ ( a , 0 ) = a ax = \gcd(a,0) = a ax=gcd(a,0)=a,易得 x = 1 , y = 0 x=1,y=0 x=1,y=0

我们知道 gcd ⁡ ( a , b ) = gcd ⁡ ( b , a   m o d   b ) \gcd(a,b) = \gcd(b, a \bmod b) gcd(a,b)=gcd(b,amodb),那么我们在知道

b x ′ + ( a   m o d   b ) y ′ = gcd ⁡ ( b , a   m o d   b ) bx' + (a \bmod b) y' = \gcd(b, a \bmod b) bx+(amodb)y=gcd(b,amodb)

的一组特解 x ′ , y ′ x',y' x,y 的情况下如何推出 x , y x,y x,y 呢?

a = ⌊ a b ⌋ ⋅ b + a   m o d   b a = \left\lfloor\dfrac{a}{b}\right\rfloor\cdot b + a \bmod b a=bab+amodb

将其代入 a x + b y = gcd ⁡ ( a , b ) ax + by = \gcd(a,b) ax+by=gcd(a,b) 中整理可得

b ( ⌊ a b ⌋ ⋅ x + y ) + ( a   m o d   b ) x = gcd ⁡ ( a , b ) b(\left\lfloor\dfrac{a}{b}\right\rfloor\cdot x + y) + (a \bmod b)x = \gcd(a,b) b(bax+y)+(amodb)x=gcd(a,b)

所以

{ ⌊ a b ⌋ ⋅ x + y = x ′ x = y ′ \begin{cases} \left\lfloor\dfrac{a}{b}\right\rfloor\cdot x + y=x'\\ x=y' \end{cases} {bax+y=xx=y

所以

{ x = y ′ y = x ′ − ⌊ a b ⌋ ⋅ x \begin{cases} x=y'\\ y=x'-\left\lfloor\dfrac{a}{b}\right\rfloor\cdot x \end{cases} {x=yy=xbax


如何用于求逆元

求方程 a x ≡ 1 ( m o d p ) ax \equiv 1 \pmod p ax1(modp) 的解本质上就是求二元一次不定方程

a x + p y = 1 ax + py = 1 ax+py=1

的解中的整数解 x x x。使用扩展欧几里得算法即可求出 x x x 的一个特解。

而我们发现,

a ( x + k p ) + p ( y − k a ) = 1 a(x + kp) + p(y -ka)=1 a(x+kp)+p(yka)=1

所以我们可以不断调整 x x x 得到通解。

也可看出,逆元存在的充分必要条件是 a a a p p p 互质。

时间复杂度 O ( log ⁡ ( a + p ) ) O(\log (a+p)) O(log(a+p))


例题代码

注意要求 x x x 的最小正整数解。

#include<iostream>
using namespace std;

int exgcd(int a, int b, int &x, int &y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	int d = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return d;
}

int main()
{
	int a, b, x, y;
	cin >> a >> b;
	exgcd(a, b, x, y);
	x %= b;
	if(x < 0)
		x += b;  //注意x可能为负数
	cout << x << endl;
	return 0;
}

线性求连续正整数的逆元

例题:Luogu P3811 【模板】乘法逆元

首先易得 1 − 1 = 1 1^{-1} = 1 11=1

然后因为 p = ⌊ p i ⌋ ⋅ i + p   m o d   i p = \left\lfloor\dfrac{p}{i}\right\rfloor\cdot i + p \bmod i p=ipi+pmodi,令 k = ⌊ p i ⌋ k=\left\lfloor\dfrac{p}{i}\right\rfloor k=ip j = p   m o d   i j=p \bmod i j=pmodi,放到模意义下就会得到
k i + j ≡ 0 ( m o d p ) ki + j \equiv 0 \pmod p ki+j0(modp)

两边同时乘 i − 1 j − 1 i^{-1}j^{-1} i1j1 得到
k j − 1 + i − 1 ≡ 0 ( m o d p ) kj^{-1}+i^{-1} \equiv 0 \pmod p kj1+i10(modp)

所以有
i − 1 ≡ − k j − 1 ( m o d p ) i^{-1} \equiv -kj^{-1} \pmod p i1kj1(modp)


i − 1 ≡ − ⌊ p i ⌋ ⋅ ( p   m o d   i ) − 1 ( m o d p ) i^{-1} \equiv -\left\lfloor\dfrac{p}{i}\right\rfloor \cdot (p \bmod i)^{-1} \pmod p i1ip(pmodi)1(modp)

代码实现(来自OI-wiki):

inv[1] = 1;
for(int i = 2; i <= n; i++)
    inv[i] = (p - p / i) * inv[p % i] % p;

使用 p - p / i 来防止出现负数,且对结果不会产生影响。

线性求阶乘逆元

∵ n ! = ( n − 1 ) ! × n \because n!=(n-1)! \times n n!=(n1)!×n

∴ ( n ! ) − 1 ≡ [ ( n − 1 ) ! ] − 1 × n − 1 ( m o d p ) \therefore (n!)^{-1} \equiv [(n-1)!]^{-1} \times n^{-1} \pmod p (n!)1[(n1)!]1×n1(modp)

∴ ( n ! ) − 1 × n ≡ [ ( n − 1 ) ! ] − 1 ( m o d p ) \therefore (n!)^{-1} \times n \equiv [(n-1)!]^{-1} \pmod p (n!)1×n[(n1)!]1(modp)

最终我们得到
[ ( n − 1 ) ! ] − 1 ≡ ( n ! ) − 1 × n ( m o d p ) [(n-1)!]^{-1} \equiv (n!)^{-1} \times n \pmod p [(n1)!]1(n!)1×n(modp)

其实不看推导过程这个也很好理解。而 ( n ! ) − 1 (n!)^{-1} (n!)1 我们可以用扩欧、欧拉定理或者费马小定理算一下就好了。

例题:

  1. SDOI2016 排列计数(这题需要其它的知识,求解的过程中要用到此方法)
  2. NOI Online #2 入门组 建设城市(这题也需要其它的知识)
  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值