小学二年级都能看懂的扩展欧几里得学习笔记
一些闲扯
上次学扩展欧几里得是两年前,结果中考复习期间不动电脑,直接忘得一干二净
然后两个月前又看了一遍,今天要用的时候发现还是不熟练(看了个寂寞属于是)
别人化身狂暴切题组长的时候我在复习
而且网上的一大堆博客看得我晕晕乎乎费老大劲才彻底搞明白,这时其他人已经a了三四道了orz
于是下定决心开了个blog,直接自己写一个小学二年级都能看懂的学习笔记,这样我再忘掉知识点的时候就直接看这篇就能秒懂了罢(希望)
这是本人第一篇blog,不知写得怎么样(虽然写得差我也改不了)
前置算法——欧几里得(辗转相除)
计算a与b的最大公约数\(gcd(a,b)\)
令 \(r=a\bmod b,k=\left \lfloor \frac{a}{b} \right \rfloor,d=gcd(a,b)\)
即 \(r=a-kb\)
又 \(d|a,d|b\)
所以 \(d|r\)
同理,令 \(gcd(b,a\bmod b)=d',d'|r,d'|b\)
所以 \(d'|kb+r,d'|a\)
故 \(gcd(a,b)=gcd(b,a\bmod b)\)
递归下去,直到 \(a'=d,b'=0\)
此时 \(gcd(a,b)=gcd(a',b')=d\)
代码如下,非常简单:
void gcd(ll a,int b){
if(!b){
return a;
}
return gcd(b,a%b);
}
拓展欧几里得
介绍
总之就是求解不定方程 \(ax+by=c\)
直接讲方法
原理
首先考虑证明对于 \(ax+by=c\) ,方程有整数解的充要条件为 \(gcd(a,b)|c\)
首先证明必要性,这非常简单。
因为 \(x,y\) 均为整数
所以 \(gcd(a,b)|ax+by\)
所以 \(gcd(a,b)|c\)
接下来证明充分性,而这就涉及到裴蜀定理
裴蜀定理
裴蜀定理内容如下:设 \(a,b\) 是不全为零的整数,则存在整数 \(x,y\) , 使得 \(ax+by=gcd(a,b)\) .
说人话就是当 \(ax+by=gcd(a,b)\) 时必然有解,当 \(gcd(a,b)|c\) 的时候自然也有解
(直接解出来 \(ax+by=gcd(a,b)\) 再乘上 \(\frac{c}{gcd(a,b)}\) 就好了)
证明如下:
设 \(s\) 为 \(ax+by\) 的最小正值, \(q=\left \lfloor \frac{a}{s} \right \rfloor,r=a\bmod s\)
显然 \(0\leq r<s\),\(r=a-s*q=a-(ax+by)*q=a(1-qx)+b(-qy)\)
可见 \(r\) 也为 \(a,b\) 的线性组合
又因为 \(s\) 为\(ax+by\) 的最小正值且 \(0\leq r<s\)
也就是说,在 \((0,s)\) 范围内不可能存在 \(r\) 满足 \(ax+by=r\)
所以 \(r\) 只能等于 \(0\),即 \(a\bmod s=0\)
所以 \(s|a\) ,同理 \(s|b\)
令 \(d=gcd(a,b)\)
由于 \(s\) 为 \(ax+by\) 最小正值,所以 \(s\leq d\)
由于 \(ax+by=c\) 有解的必要条件为 \(gcd(a,b)|c\)
所以 \(d|s\) ,即 \(d\leq s\)
所以 \(s=d=gcd(a,b)\)
证毕
解方程
在证明了上面的结论后,我们就可以尝试解决 \(ax+by=c\) 了
首先由于只有 \(gcd(a,b)|c\) 时方程有解,不妨先解出方程 \(ax+by=gcd(a,b)\) ,再将解乘上 \(\frac{c}{gcd(a,b)}\) 即可
对于
上面一部分或许有点绕。简而言之,我们列出了两个方程:
\(ax+by=gcd(a,b)\) 与 \(bx_1+(a\bmod b)y_1=gcd(b,a\bmod b)\)
根据 \(gcd(a,b)=gcd(b,a \bmod b)\)
可得 \(ax+by=bx_1+(a\bmod b)y_1\)
然后将右边表示成 \(ay_1+b(x_1+\lfloor \frac{a}{b}\rfloor y_1)\) 的形式
由于 \(ax+by=ay_1+b(x_1+\lfloor \frac{a}{b}\rfloor y_1)\)
不难发现,如果知道 \(x_1,y_1\) ,则原方程必有一组满足条件的解 \(x=y_1,y=x_1+\lfloor \frac{a}{b}\rfloor y_1\)
而为了解出 \(x_1,y_1\) ,我们可以仿照欧几里得求最大公因数的过程,递归下去,解出 \((a \bmod b)x_2+(b\bmod (a\bmod b))y_2=gcd(a,b)\) 中的 \(x_2,y_2\)
以此类推解出 \(x_3,y_3,x_4,y_4……\)
我们假设我们得到这么一个方程 \(a'x_n+b'y_n=gcd(a,b)\)
根据前面欧几里得算法可得知,当 \(b'=0\) 时, \(a'=gcd(a,b)\)
此时原方程可表示为 \(gcd(a,b)\cdot x_n+0y_n=gcd(a,b)\)
显然此方程有一组解 \(x_n=1,y_n=0\)
将其递归回去,即可解出 \(x,y\)
代码也是非常简单
void exgcd(ll a,int b,ll &x,ll &y){
if(!b){
x=1,y=0;
}
else{
exgcd(b,a%b,y,x);//此时 x=y1,即为方程的解,y=x1
y-=x*(a/b); //此时 y=y-x*(a/b)=x1-y1*(a/b) 为方程的解
}
}

浙公网安备 33010602011771号