扩展欧几里得的应用
本随笔只想随便写一写关于自己学习扩展欧几里得算法的一些理解和一些应用和一些理解!
本随笔的参考资料有:刘汝佳的白色和紫色两本书,《算法导论》里关于模运算那后面的一些章节,还有这个博客http://www.acmerblog.com/extend-gcd-5610.html ,对此表示感谢!
首先,我在这里不详细讨论扩展欧几里得算法的证明过程,我在这里只是讨论一下他的应用(有点功利)
1: 基本算法:
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by,也就是如果要让我们的这个不定方程成立必须满足的条件,我们这里上一下代码(刘汝佳训练指南)
#include <stdio.h> typedef long long ll; ll exgcd(ll a, ll b, ll &d, ll &x, ll &y) { if(!b) { d = a; x = 1; y = 0; } else { exgcd(b, a%b, d, y, x); y -= x * (a / b); } return d; } int main() { ll d, x, y; d = exgcd(45, 30,d, x, y); printf("%lld %lld %lld\n\n", d,x,y); }
我们这里解释下传递的参数:45,30,就是相当于我们的a,b然后我们的这个代码其实只是讨论他的一种最基本的情况,d是他的一个gcd(a,b), 然后x,y就是我们自动求出来的满足等式的值(理解一下这个代码的逻辑关系,就是我们的不定的值只有a,b,然后d,x,y都是根据我们已有的公式自动求出来的)
1 : 求解不定方程:ax+by=c。我们不妨这么思考,就是两个数字是45,30,c是30,那么我们的结果会怎么样?首先,gcd(45,30)=15, 30可以整除15,所以我们的方程应该是有解的;如果把c换成了23,那么我们的方程就是无解,所以修改的代码如下:
#include <stdio.h> typedef long long ll; ll exgcd(ll a, ll b, ll &d, ll &x, ll &y) { if(!b) { d = a; x = 1; y = 0; } else { exgcd(b, a%b, d, y, x); y -= x * (a / b); } return d; } int main() { ll d, x, y; ll a, b ,c; scanf("%lld%lld%lld", &a, &b, &c); d = exgcd(a, b,d, x, y); if(c % d == 0) { ll k = c / d ; x = x * k; y = y * k; printf("%lld %lld\n", x, y); } else { printf("该不定方程无解\n"); } return 0; }
但是我们还是有一点可以思考一下,就是我们可不可以通过这个来求最值?
2:求解模线性方程 ax≡b (mod n) ,其实这个等价于相当于求解方程 ax+ ny= b, (x, y为整数),其实这一步十分好得到,其实就是ax%n = b % n = k,然后我们列两个等式其实就可以把答案得到了,其实不难~所以代码和我们上面的代码是一样,只是多了一个转换的过程~
3 :求解逆元,但是逆元这个概念,我还不是很清楚,就是不清楚,我的逆元求解出来了到底有什么作用?这个我再看看~
好了,今天来补充一下~
逆元的一个作用就是在连乘的时候,我们求a*b*c*d*e*f*g..../z 前面乘积部分LL存不下所以要一边mod一边乘
最后处理到除z时,不一定能除尽。比如(8/2)%5 ,我们8 % 5 = 3, 3除不尽2啊,如果我们还是强行算的话,很明显会出问题的撒,怎么办呢?我们就让3乘2%5的逆元,最后再mod5,这样就可以了。相当于把除法变成了乘法~~~