扩展欧几里得与同余方程

额…晚上听学长讲了扩展欧几里得,听得迷迷糊糊的,还是要怪自己没有提前去预习,甚至不知道这个算法能干啥…学长讲完之后自己去翻了将近两个小时的博客才稍微能理解一点。

扩展欧几里得

欧几里得算法gcd(a,b)可以算出a,b的最大公因数(后面就把这个最大公因数用g来表示吧),扩展欧几里得就是在算出g的同时算出x,y满足:
ax+by=g

这里其实有个贝祖定理:
即如果a、b是整数,那么一定存在整数x、y使得ax+by=g。

换句话说,如果ax+by=m有解,那么m一定是g的若干倍。(可以来判断一个这样的式子有没有解)

先看看欧几里得的代码

int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}

上面代码可以求出g,我们不难发现在递归结束时
b=0,a=g,且此时满足 ax+by=g,所以可以得出x=1,y=0
但是这时的a,b已经不是开始的那个a,b了,所以我们需要回到最初的模样(突然非主流哈哈哈哈哈)。

因为我求g用的是递归,所以我们如果知道这一层与下一层x,y与x1,y1的关系,就能一层层的推回原来的a,b所对应的x,y。
假设我们已经递归到了下一个状态
b*x1+(a%b)*y1=gcd

首先我们要知道a%b=a-(a/b)*b(不理解的话找两个数代入就懂了)代入上式可得

b*x1 + (a-(a/b)*b)*y1

= bx1 + ay1 – (a/b)by1

= ay1 + b(x1 – a/b*y1) = gcd

可以发现 x=y1,y=x1-a/b*y1

既然找到了关系那么就能在求g的同时求出x,y了

int ex_gcd( int a, int b,int& x ,int& y  ){
	if( b == 0){
		x = 1;
		y = 0;
		return a;//递归到边界,开始返回上一层
	}
 	
	 int g = ex_gcd( b,a%b ,x,y);
	 int t = x; 
	 x = y;
	 y = t - a/b * y;
	 return g;
} 
int main(void){
	int a,b,g,x,y;	
	scanf("%d%d",&a,&b); 
	g = ex_gcd(a,b,x,y);
	printf("%d * %d + %d * %d = %d",a,x,b,y,g);
	return 0;
}

同余方程(求逆元)

什么是逆元呢?
a*x≡1(mod b)
即a乘x对b取模等于1,那么a与x关于b互为乘法逆元

对于整数a,b只有当gcd(a,b)=1时才能求a对b的乘法逆元

ax ≡ 1 (mod b) 可以写成 ax-bk=1,观察上面的拓欧ax+by=gcd(a,b)
当gcd(a,b)=1时有a
x+b*y=1
所以我们只需令k = -y,就可以用扩欧来求逆元了

用这种方法求出来的x,可能不是最小正整数,
我们只需让x=(x%b+b)%b,即可求出最小的正逆元了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值