数论 · 逆元

本文详细介绍了求解模运算逆元的三种方法:费马小定理结合快速幂、扩展欧几里得算法以及线性递推。通过费马小定理证明和扩展欧几里得算法的运用,可以高效地在模意义下找到一个数的逆元。同时,文章还提供了相应的代码实现,并以线性递推法为例,展示了如何在模板题中应用这些方法。
摘要由CSDN通过智能技术生成

前言

针对比赛学的一点点逆元,在这里记录一下其中一种方法。

当然求逆元的方法有很多种,之后学到再回来写。 —— 2021.8.24

UPDATE

  • 2021 - 11 - 25 填坑。

    添加了两种求逆元的方法 + 修改了一些写得不好(难看至极)的地方

  • 2021 - 12 - 01 补充了欧拉定理的证明。

定义

a x ≡ 1 ( m o d b ) ax \equiv 1\pmod b ax1(modb) a ⊥ b a\perp b ab(a,b 互质),

则称 x x x a a a 的逆元。

一、费马小定理 + 快速幂

若 p 为质数,且 q ⊥ p q \perp p qp,根据费马小定理,有 q p − 1 ≡ 1 ( m o d p ) q^{p-1} \equiv 1 \pmod {p} qp11(modp)

带入原柿子中就有:

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

∴ x ≡ a p − 2 ( m o d p ) \therefore x \equiv a^{p-2} \pmod p xap2(modp)

然后直接用快速幂求解即可。

代码

省略快速幂。

inline int fermat (int a, int n)
{
	return pow_mod (a, n - 2, n);
}


补:费马小定理证明

费马小定理实际上就是 欧拉定理(证明) 的一个特殊情况。

我们定义 φ x \varphi_{x} φx 为从 1 到 x 和 x 互质的整数的数量。

例如: φ 8 = 4 \varphi_{8}=4 φ8=4,分别是:1、3、5、7。

欧拉定理就是: x φ p ≡ 1 ( m o d p ) x^{\varphi_p} \equiv 1 \pmod p xφp1(modp)

而费马小定理就是当 p 为质数时的一个特殊情况 。

易证,当 p 为质数时, φ p = p − 1 \varphi_p=p-1 φp=p1

所以当 p 为质数时, x p − 1 ≡ 1 ( m o d p ) x^{p-1} \equiv 1 \pmod p xp11(modp)



二、扩展欧几里得

∵ a x ≡ 1 ( m o d p ) ( x 为逆元 ) \because ax \equiv 1 \pmod p (\text{x 为逆元}) ax1(modp)(为逆元)

∴ a x + b y = 1 \therefore ax + by=1 ax+by=1

这样就可以直接用扩欧求逆元了。

但对于一次性求许多逆元(如洛谷的模板),效率并不高。

数论·扩欧

代码

省略扩欧代码。

inline int exgcd_inv (int a, int n)
{
	int gcd, x, y;
	gcd = exgcd (a, n);//求解方程 ax + ny = gcd (a, n)
	return d == 1 ? (x + n) % n : -1;
}

三、线性求逆元

首先,有 1 − 1 ≡ 1 ( m o d p ) 1^{-1} \equiv 1\pmod p 111(modp)

再设 p = k ∗ i + r ,   r < i ,   1 < i < p p=k*i+r,\ r<i,\ 1<i<p p=ki+r, r<i, 1<i<p

这样就有 k ∗ i + r ≡ 0 ( m o d p ) k * i + r \equiv 0 \pmod p ki+r0(modp),然后给两边同乘上 i i i 的逆元和 r r r 的逆元,

可化简得到: k ∗ r − 1 + i − 1 ≡ 0 ( m o d p ) k * r^{-1} + i ^{-1} \equiv 0 \pmod p kr1+i10(modp)

易知: k = [ p i ] ∗ ,   r = p   m o d   i k=\left[\dfrac{p}{i}\right] * ,\ r = p \bmod i k=[ip], r=pmodi

带入上柿可得:

i − 1 ≡ − [ p i ] ∗ ( p   m o d   i ) − 1 ( m o d p ) i^{-1} \equiv -\left[\dfrac{p}{i}\right] * (p \bmod i)^{-1} \pmod p i1[ip](pmodi)1(modp)

这样就可以用递推求出逆元了。

代码

建数组 i n v [ ] inv[] inv[] i n v i inv_i invi 表示 i i i 的逆元。就有:

inv[i] = -(p / i) * inv[p % i];

用这个方法过了模板题的代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define rint register int
const int maxn = 3e6 + 5;
int inv[maxn], n, q;

signed main ()
{
	scanf ("%lld %lld", &n, &q);
	inv[1] = 1;
	printf ("1\n");
	for (rint i (2); i <= n; ++i)
	{
		inv[i] = ((-(q / i) * inv[q % i]) % q + q) % q;
		printf ("%lld\n", inv[i]);
	}
	return 0;	
} 

—— E n d End End——

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值