关于逆元 - 逆元的三种解法

作为数论的基础,感觉逆元还是很有用的,基本取模和除法的地方就有它

首先这个东西的定义就是在模 p 意义下,a 乘上自己的逆元等于 1 ,就相当于模 p 意义下的倒数

共三种常用解法,我们今天还是注重一些实践方面,证明的话就略了(绝对不是我忘记了怎么证qwq 。 我们三个方法,各有好坏,也会在最后评述

费马小定理

这个是最简单的,当模数是一个质数 p ,a 关于 p 的逆元就是 \(a ^ {p-2}\) ,就这么轻松愉快

证法比较烦, 大概是构造一个余数集合之类的,个人认为不太重要(?

那么很显然这个可以用快速幂做到 \(O(\log N)\)

优点

  1. 编码极其简单,熟练后可以迅速使用
  2. 单词查询逆元时间复杂度优秀

缺点

  1. 条件苛刻
    需要是一个质数模数,那么出题人毒瘤些整合数模数费马小定理就废了

当然,在大部分综合题里,费马小定理依然是应用场景最广泛的逆元求法

扩展欧几里得算法

这个其实学完扩欧理解很容易,没学过也不难。

扩欧其实只干了一件事,就是求

\[ax + by = \gcd(a,b) \]

这么一个式子,然后像辗转相除一样,利用 \(\gcd(a,b) = \gcd(b , a \% b)\) 一路递归求一组特解

那么我们可以看问题了,相当于是求模 \(p\) 意义下

\[ax \equiv 1 \]

这个是不是直接代入就好了

\[ax = 1 + py \]

p正负无关所以就等于

\[ax + py = 1 \]

求完 \(x\) 的特解即为逆元

聪明的小朋友就看出来了,那你这个式子是不是必须得 \(\gcd(a,p) = 1\) 呢?对的对的,也就是求逆元的数要和模数互质

复杂度同欧几里得算法

优点
1.快
2.使用范围比费马小定理更加广泛
只要所求数与模数互质即可,这意味着如果 p 是一个巨大的合数,你就可以用这个求

缺点
1.编码其实不是很简单,代码虽短,如果不背,每次脑子过一遍还是有些麻烦

那么其实单次查询的方法就这俩,都是\(O(\log N)\) 的,如果要一次求一堆逆元呢?

递推

我们可以把模数 \(p\) 这样表示

\[p = qx + r \]

那么 $$x \equiv \frac{p - r}{q} \equiv -\frac{r}{q}$$

很显然这个的逆元是\(- \frac{q}{r}\) ,搞一个数组 inv 存逆元,也就是 \(- (p / x)\times inv_{p \% x}\)

这个挺有趣的,可以放下代码

#include <bits/stdc++.h>
#define ll long long
const int N=3e6+7;
ll n,p; ll a[N];

namespace P3811
{	
	inline void write(int x) {
	    if(x<0)putchar('-'),x=-x;  if(x>9)write(x/10); putchar(x%10+'0');return;   
	}
	inline ll read() {
           int x=0,f=1; char ch=getchar();
	   while(ch<'0'||ch>'9')  {if(ch=='-') {f=-1;}  ch=getchar();}  while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();  
	    return x*f;
	}
	
	void main()
	{ 
		n=read(),p=read(); a[1]=1;putchar('1'); putchar('\n');
		for(register ll i=2;i<=n;i++) {
			a[i]=(p-p/i)*a[p%i]%p; write(a[i]); putchar('\n');
		}
	}
}
int main(){P3811::main();}

洛谷P3811

复杂度 \(O(N)\)

那么逆元就告一段落了

posted @ 2025-03-14 22:42  一Kx一  阅读(185)  评论(0)    收藏  举报