学习笔记——逆元

蒟蒻初次写笔记,一定有许多不完善的地方,欢迎大佬们来踩一踩!

逆元的概念


什么是逆元?我们在提及逆元的时候通常指的是乘法逆元。满足

a*k≡1 (mod p)

的k值就是a关于p的乘法逆元。


逆元的作用

首先来举一个例子:

假设在一种算法中,现有a、b和p三个整数,我们希望求出 (a/b) mod p。

乍一看这样的计算很简单,按照正常顺序算即可。但是在很多程序里,a、b的值需要自行求解,这时要考虑在求解过程中会不会有变量溢出的现象发生。

那么怎么办呢?我们可以试着把取模运算提前,从而得到 (a mod p)/(b mod p)。
然而试了几个数,发现WA了。这是怎么了?

这是因为取模等式的变形中不涉及除法,且其推导式中也没有除法。关于取模运算的几个基本性质,可以访问这里

但是根据取模等式内容,我们却可以推导出(a*k) mod p这样的方法,其中k是b关于p的逆元。

让我们来证明一下这个方法的可行性:(证明过程中涉及取模运算的变形,如果你不熟悉请先点击上面的链接了解)

 

逆元的正确性


 

 

首先,我们已经有了k 是b关于p的逆元的前提条件了。

那么我们可以得到b*k≡1 (mod p)

进而得到b*k=p*k+1

则k=(p*x+1)/b

在得到k之后我们可以将它代入之前的式子(a*k) mod p得到

  (a*(p*x+1)/b) mod p

     =((a*p*x)/b+a/b) mod p (乘法分配律)

     =(((a*p*x)/b) mod p+(a/b) mod p) mod p

     =((p*(a*b)/b) mod p+(a/b) mod p) mod p

因为 (p*(a/b)/b) mod p=0

所以 原式等于 (a/b) mod p。

 

 

实现求逆元


 

 

考虑使用扩展欧几里德(Extended Gcd)算法来实现这个求解方法。

为了使这一算法,首先介绍欧几里得算法

欧几里得算法是一种以较快速度求解两个数的最大公约数的方法。由于本方法比较简单,故直接给出代码。

int Gcd(int a,int b){
	if(b==0) return a;
	else gcd(b,a%b);
}

 假设我们现在已经求得Gcd(a,b),那么对于a*x+b*y=Gcd(a,b),一定有至少一组x,y满足等式。

在a>b的前提下,我们分两种情况考虑:

在第一种情况下,b=0。那么此时Gcd(a,b)=a,则此时必有x=1,y=0。

在第二种情况下,a>b>0,那么此时应该有

a*x1+b*y1=Gcd(a,b) 我们称其为1式

b*x2+(a mod b)*y2=Gcd(b,a mod b) 我们称其为2式

根据之前的欧几里得算法,我们能得到Gcd(a,b)=Gcd(a,a mod b),因此1式和2式可以一起变为:

a*x1+b*y1=b*x2+(a mod b)*y2 我们称其为3式

为了理解下面的内容,我们有必要再次重温取余的计算方式。对于 a mod b,实际上我们是在计算 a-[a/b]*b。请注意此处 [ ] 的意义是取最大的整数使其小于方括号内的数。例如[3.254]=3。

有了这样的基础,我们很容易地将3式进行变形,最终得到:

a*x1+b*y1≡a*y2+b(x2-[a/b]y2)

根据恒等式定理,我们能推得

x1=y2 且 y1=x2- [a / b] *y2

那么我们只要能获得x2,y2,那么我们就能获得x1,y1

以上方法均可以通过递归实现,相应的代码如下:

/*
import guide:
int x,int y should be set as a public variable
ALWAYS call the function getAnswer() 
DO NOT call the function _exGcd() for it is not complete.
*/
int _exGcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int res=_exGcd(b,a%b,x,y);
	int aux=x;
	x=y;
	y=aux-(a/b)*y;
	return res;
}
int getAnswer(int a,int b){
	int ans;
	_exGcd(a,b,x,y);
	ans=x+b;//bookmark 1#
	return ans;
}

 至此,得到了a关于b的逆元。如果需要进行取模,应把注释为“bookmark 1#”的代码行替换成

	ans=(x+b)%MOD;// MOD is the target nuber for  modulo

 

转载于:https://www.cnblogs.com/NicholasFlare/p/9876318.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值