ACM_扩展欧几里得算法

我们先来回顾一下欧几里得算法,欧几里得算法是用于求两个数的最大公约数:其核心为一句 Gcd(a, b) = Gcd(b, a%b) (Gcd表示两个数的最大公约数),直到a%b == 0时,可得到Gcd(a,b)的具体值。

我们再来看一下扩展欧几里得算法在乘法逆元上的运用,先来介绍一下乘法逆元,可能一些没有学过离散数学的同学并不知道逆元是什么,集合中的某一个数与其逆元做相应的二元运算得到的就是这个集合的单位元,这就是逆元……(可能没学过离散数学的同学单位元也不知道是什么=.=),在集合中的某一个数与这个集合的单位元做相应的二元运算得到的是这个数本身,这就是单位元,在我们的乘法运算中,单位元自然就是1,这个好理解,因为1*x = x,x*1 = x。

了解了这些概念后,现在我们来看在MOD m的乘法下的逆元,可能有些同学又想问了,我们为什么要求逆元呢,小编不得不承认小编一开始也觉得莫名其妙……感觉这东西求出来并没有什么卵用,为什么我们要求这个逆元?答案很简单,因为平时我们习惯了乘法的逆运算是除法,但是二元运算并不一定都存在逆运算,在MOD m的乘法下就不存在,我们不能用除法,除法不满足同余的性质,举个简单的例子,5%3 = 2,4%3 = 1,显然(5/4)%3 != (5%3)/(4%3),所以我们在MOD m的乘法下涉及到除法的话我们就得用乘其逆元来代替

讲了这么多为什么要求逆元终于要讲到求逆元的方法问题了=.=, 扩展欧几里得算法就是一个经典求解乘法逆元的方法

设x为a的逆元,则满足a*x%m == 1,这个式子也可以写成a*x+m*y = Gcd(a,m),如果我们把a,m看出常数的话,现在相当是一个关于x,y的二元一次方程,显然方程的解有无数组,但是我们只需要求得其中的一组就就可以表示其他组了(线代上称之为一组基向量,小编知道很多学ACM的同学并不一定学过线代和离散,所以小编尽量用通俗的语言来讲解),显然通过小编最上面的一个讲解Gcd(a, b) = Gcd(b, a%b) (一些同学是不是觉得看到这里才知道原来第一句是有用的……),我们可以得到另一个方程m*x1+a%m*y1 = Gcd(a,m),这两个方程的右边都是相等的,同为Gcd(a,m),我们来找一下这两个式子之间的关系,因为a%m可以写作(a - (a/m)*m)那么第二个式子我们就可以写作

Gcd(a,m) = m*x1+a%m*y1

= m*x1+((a - (a/m)*m))*y1

= a*y1+m*(x1-(a/m)*y1) = a*x+m*y

所以我们得到x = y1, y =x1-(a/m)*y1。 显然当我们的a%b == 0时,x = 1, y = 0,所以我们也可以像欧几里得算法那样用递归去写它。

void exGcd(LL a, LL b, LL &x, LL &y)
{
	if(b == 0)
	{
		x = 1;
		y = 0;
		return ;
	}
	exGcd(b, a%b, y, x);
	y -= x*(a/b);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值