当前位置: 首页 > article >正文

【蓝桥杯】Python算法——求逆元的两种算法

目录

  • 零、前言
  • 一、逆元
  • 二、扩展欧几里得算法
  • 三、费马小定理
  • 四、总结

零、前言

距离25年蓝桥杯还有大概三个月时间,接下来重点应该会放在蓝桥杯备考方向,一起努力,一起加油


一、逆元

什么是逆元?这是数论中的一个基本概念。如果存在 a x ≡ 1 ( m o d   n ) ax\equiv1(mod \ n) ax1(mod n) x x x a a a在模 n n n意义下的逆元。可以简单地理解为,求一个 x x x使得 a x   m o d   n = 1 ax\ mod\ n=1 ax mod n=1
逆元的意义在哪呢?如果遇到需要求 a / b   m o d   n a/b\ mod\ n a/b mod n的情况,则可以转化为分子a乘以分母b的逆元的形式,这样我们将除法转化为乘法,提高了计算效率。


二、扩展欧几里得算法

那么怎么求解逆元呢?由前面给出的公式 a x ≡ 1 ( m o d   n ) ax\equiv1(mod \ n) ax1(mod n),不难看出求逆元 x x x就是求解等式的解: a x + n y = 1 ax + ny = 1 ax+ny=1因为 ( a x + n y )   m o d   n = a x   m o d   n (ax+ny)\ mod\ n = ax\ mod\ n (ax+ny) mod n=ax mod n,求出了 x x x y y y,那么 x x x就是 a a a的逆元。
为了方便推导,我们暂时把 n n n换成 b b b,等号右边换位 m m m,求解的更一般的形式。 a x + b y = m ax+by=m ax+by=m根据裴蜀定理:对于任意整数 a a a, b b b, m m m,求解未知整数 x x x, y y y时,必须满足 g c d ( a , b ) ∣ m gcd(a,b)|m gcd(a,b)m,即 m m m g c d ( a , b ) gcd(a,b) gcd(a,b)的倍数时才有解。
所以我们将计就计,如果 m m m g c d ( a , b ) gcd(a,b) gcd(a,b)的一倍,也就是 m = g c d ( a , b ) m = gcd(a,b) m=gcd(a,b),先解出方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的解 x 1 x_1 x1, y 1 y_1 y1,然后两边乘以 m / g c d ( a , b ) m/gcd(a,b) m/gcd(a,b),不就能求出来我们想要的了吗? a m x 1 g c d ( a , b ) + b m y 1 g c d ( a , b ) = m a\frac{mx_1}{gcd(a,b)}+b\frac{my_1}{gcd(a,b)}=m agcd(a,b)mx1+bgcd(a,b)my1=m所以,我们进一步研究问题:解出方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的解。
那么我们需要求出三个东西, x x x y y y g c d ( a , b ) gcd(a,b) gcd(a,b),这就是扩展欧几里得算法的根本研究问题。(By the way,欧几里得算法就是求解 g c d ( a , b ) gcd(a,b) gcd(a,b),方法就是我们熟知的辗转相除法。)
b = 0 b=0 b=0,有特解 x = 1 , y = 0 x=1,y = 0 x=1,y=0,这是迭代的初始条件。
b ≠ 0 b\neq0 b=0,假设 x 1 x_1 x1 y 1 y_1 y1 a x 1 + b y 1 = g c d ( a , b ) ax_1+by_1=gcd(a,b) ax1+by1=gcd(a,b)的解,根据欧几里得算法: g c d ( a , b ) = g c d ( b , a   m o d   b ) gcd(a,b) = gcd(b,a\ mod\ b) gcd(a,b)=gcd(b,a mod b),下一步我们构造 b x 2 + ( a   m o d   b ) y 2 = g c d ( b , a   m o d   b ) bx_2+(a\ mod\ b)y_2 = gcd(b, a\ mod\ b) bx2+(a mod b)y2=gcd(b,a mod b),
a   m o d   b a\ mod\ b a mod b怎么表示?不就是 a / b a/b a/b的余数嘛,所以你细品:a%b = a - (a//b)*b,( a ÷ b = q … … r a \div b = q……r a÷b=q……r,则 a = b ∗ q + r a = b*q + r a=bq+r,其中q就是a整除b的结果a//b), 带入到上式则有 b x 2 + ( a   m o d   b ) y 2 = b x 2 + ( a − ( a / / b ) b ) y 2 = g c d ( b , a   m o d   b ) bx_2+(a\ mod\ b)y_2 = bx_2+(a - (a//b)b)y_2 = gcd(b,a\ mod\ b) bx2+(a mod b)y2=bx2+(a(a//b)b)y2=gcd(b,a mod b)
好乱,整理一下:
{ a x 1 + b y 1 = g c d ( a , b ) b x 2 + ( a − ( a / / b ) b ) y 2 = g c d ( b , a   m o d   b ) g c d ( a , b ) = g c d ( b , a   m o d   b ) \left\{ \begin{aligned} ax_1 + by_1 &= gcd(a,b) \\ bx_2+(a - (a//b)b)y_2 &= gcd(b,a\ mod\ b) \\ gcd(a,b) &= gcd(b,a\ mod\ b) \end{aligned} \right. ax1+by1bx2+(a(a//b)b)y2gcd(a,b)=gcd(a,b)=gcd(b,a mod b)=gcd(b,a mod b)这样我们就能找到 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2,y_2) (x2,y2)的关系了: a x 1 + b y 1 = a y 2 + b ( x 2 − ( a / / b ) y 2 ) ax_1+by_1 = ay_2 + b(x_2 - (a//b)y_2) ax1+by1=ay2+b(x2(a//b)y2),所以有 { x 1 = y 2 y 1 = x 2 − ( a / / b ) y 2 \left\{ \begin{aligned} x_1 &= y_2\\ y_1 &= x_2 - (a//b)y_2 \end{aligned} \right. {x1y1=y2=x2(a//b)y2这就是递归的关系式。
有了初始值与递归关系,就可以写代码来求解了。

def exgcd(a,b):
	if b==0:
		return a,1,0
	gcd,x2,y2 = exgcd(b,a%b)
	x1,y1 = y2,x2-(a//b)*y2
	return gcd,x1,y1

别忘了我们求的是 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b),而我们要求的是 a x + b y = m ax+by=m ax+by=m,那么对于函数输出,还要再乘以 m / g c d m/gcd m/gcd

def Func(a,b,m):
	gcd,x1,y1 = exgcd(a,b)
	if m % gcd != 0:return None,None,None
	x0, y0 = x * m // gcd, y * m // gcd
	return gcd, x0, y0

汇总:

def exgcd(a,b):
	if b==0:
		return a,1,0
	gcd,x2,y2 = exgcd(b,a%b)
	x1,y1 = y2,x2-(a//b)*y2
	return gcd,x1,y1
	
def Func(a,b,m):
	gcd,x1,y1 = exgcd(a,b)
	if m % gcd != 0:return None,None,None
	x0, y0 = x * m // gcd, y * m // gcd
	return gcd, x0, y0

MOD = 1e9+7
a = int(input())
_, inv_a, _ = Func(a, MOD, 1)
print(inv_a)

三、费马小定理

费马小定理
如果 p p p是素数,且 a a a是一个不能被 p p p整除的整数,那么: a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1({\mathrm{mod}}p) ap11(modp)

这给了我们一个求逆元的好方法: a a p − 2 ≡ 1 ( m o d   p ) aa^{p-2}\equiv1(mod\ p) aap21(mod p)注意前提:模数为素数,且 a a a不能被 p p p整除。
这时我们只需要算一下 a p − 2 a^{p-2} ap2就行了,很方便吧。可以用快速幂来求。

def KSM(a, b, mod):
	if b == 0: return 1
	if b == 1: return a % mod
	res = KSM(a, b//2, mod)
	res = res * res % mod
	if b % 2 == 1:
		res = res * a % mod
	return res

def INV(a):
	return KSM(a, MOD-2, MOD)

MOD = 1e9+7
a = int(input())
print(INV(a))

四、总结

介绍了两种方法求解逆元:扩展欧几里得算法和费马小定理算法,前者实用性广,而后者有一个前提,即模数必须为素数,不过一般用费马小定理的情况要多一些。


http://www.kler.cn/a/511394.html

相关文章:

  • 将IDLE里面python环境pyqt5配置的vscode
  • Spring Boot 集成 MongoDB:启动即注入的便捷实践
  • Amazon MSK 开启 Public 访问 SASL 配置的方法
  • 第5章:Python TDD定义Dollar对象相等性
  • 【Idea】编译Spring源码 read timeout 问题
  • 第17章:Python TDD回顾与总结货币类开发
  • 4 AXI USER IP
  • 分布式IO模块在电动工具转子生产线的智能化转型
  • [创业之路-255]:《华为数字化转型之道》-1-主要章节、核心内容、核心思想
  • Flink (七): DataStream API (四) Watermarks
  • GoLang 微服务学习笔记
  • 在 Vue 3 中实现插件化架构:设计可扩展的前端插件系统
  • 学习MyBatis的调优方案
  • 第14章:Python TDD应对货币类开发变化(一)
  • PyTorch 卷积神经网络全解析:从原理到实践
  • Ubuntu22.4挂载大于2.2T磁盘(27T大磁盘)
  • 递归练习三(决策树)
  • 53,【3】BUUCTF WEB october 2019 Twice SQLinjection
  • 82.提取条件模式
  • BUUCTF_Web([GYCTF2020]Ezsqli)
  • Linux中的文件上传和下载
  • 前后端分离的Java快速开发平台
  • 【万图找码】在大量图片中快速找出有二维码的图片
  • TP4056锂电池充放电芯片教程文章详解·内置驱动电路资源!!!
  • Web3 时代,区块链与物联网的融合创新前景
  • Axios 封装:处理重复调用与内容覆盖问题