浅谈欧几里得 与 扩展欧几里得

灵乌路空

2019-05-15 07:59:50

Personal

## $$ \text{ 浅谈欧几里得 与 扩展欧几里得:} $$ $Baka$阿空 实在是太 ⑨了 , 没脑子的他只能整理在这里: 如果以下内容中存在错误 , 请及时通知博主 , 博主会非常感谢您的指正 , 并欢迎您把蠢货博主的头 **拧下来** 于 $2019.5.15$ 创建 于 $2019.5.17$ 修复了 $bug$ , 感谢 @[zZZ_han](https://www.luogu.org/space/show?uid=128119) 的帮助 于 $2019.5.19$ 更新了 **求解同余方程组** 于 $2019.8.09$ 修复了 $bug$ ,并调整了排版 ------------ ## 目录 : 浅谈欧几里得 与 扩展欧几里得 - 小约定 - 欧几里得定理 - 证明 - 简单应用 - 裴蜀定理 - 欧几里得扩展 - 证明 - 应用 - 解不定方程 - 解同余方程 - 解模的逆元 - 求解同余方程组 ------------ $$ \text{从此开始,一个天文单位} $$ $$ \large\downarrow $$   ------------ ### 在开始前的一些小约定 ~~(因为自己记不住)~~ : - 下取整: $\lfloor x\rfloor = $不超过 $x$ 的最大整数. 例: $\lfloor 5.5\rfloor = 5$ , $\lfloor -1.5\rfloor = -2$. - 取模运算: $x \mod p=$ $x$ 除以 $p$ 的余数.简记为: $x \% p$ ; 则: 可以这样表达除法: $a=\lfloor \dfrac{a}{p}\rfloor\times p + a\% p$ 其中, $a$ 为被除数 , $p$为除数 , $\lfloor \dfrac{a}{p}\rfloor $ 为商 , $a \% p$ 为余数 。 - 模意义:使用$\pmod p$ , 代表 运算的中间值和答案 都对 $p$ 取模. ------------ ## 1.欧几里得定理: #### $\large \gcd(a,b) = \gcd(b,a\% b)$ #### 当 $b=0$ 时 ,有 $\gcd(a,b)= \mid a\mid$ ; - 感谢cyh学长 [@King丨帝御威](https://www.luogu.org/space/show?uid=68622) 的证明 : 设 : $a,b$ 的最大公约数为 $c$ **则 :** $a=nc\ ,\ b=mc$ , $(n,m \in Z)$ , 设$a=k\times b + r$ **则 :** $r=a\%b=a-k b=nc-kmc=(n-km)c$ 若要使 $\gcd(a,b) = \gcd(b,a\%b)$ , 则需要证 : $b , r$ 的最大公约数也为 $c$ , **即 :** $b=m\times c , r=(n-km)\times c$ 中 , $m , (n-km)$ 互质 。 - 子证明: 用反证法 , 设存在 $d$ 为 $m,(n-km)$ 的最大公约数,且 $d > 1$。 设 : $n-km=qd$ , $m=pd$ , $(q,p \in Z)$ **则 :** $b = mc = pdc\ $ , $\ a=kb+r=kpdc + qdc=dc(kp+q)$ **则 :** $a$ 还存在一个因数为 $dc$ ; 因为 $d>0,c>0$ , 则有: $dc > c$ **此结论与 $a,b$ 的最大公约数为 $c$ 相矛盾** **故 :** 不存在 $d>1$ 作为 $m,(n-km)$ 的最大公约数 **则 :** $m,(n-km)$互质 ,子证明成立。 由子证明 ,得: $b=mc , r=(n-km)c$ 中 , $m,(n-km)$ 互质 。 **则: $b$ 与 $r$ 的最大公因数仍为 $c$** 证毕 。 ------------ - 应用: 有了以上的知识,我们便可以写出一个求$a,b$ 的 $\gcd(a,b)$ 的函数了 由 欧几里得定理可得 , 可通过递归求得 $\gcd(a,b)$ 的值 递归边界即: 当 $b=0$ 时,$\gcd(a,b)=a$ ; 简单的代码实现: ```cpp int gcd(int a,int b) { if(b) return gcd(b,a%b); else return a; } ``` 也可以写成一行: ```cpp int gcd(int a,int b) { return b?gcd(b,a%b):a; } ``` ------------ ## 2. 裴蜀定理: #### 设 $a,b$ 为不全为 $0$ 的整数 , #### 则存在整数 $x,y$ ,使得 $\large ax + by = \gcd(a,b)$ 。 特别地 , $\gcd(a,b)=1$ $\Leftrightarrow$ 存在 $x,y \in Z$ , 使: $ax+by = 1$ ; 那么该如何证明 定理的正确性 呢 ? 请继续往下看: ## 3. 扩展欧几里得: #### 对于不完全为 $0$ 的两个数 $a,b$ , 必然存在 无限个 $x,y$ ,使方程 #### $\large ax + by = \gcd(a,b)$成立 - 证明: 设$a>b$ 1.当$b=0 $时 , $\gcd(a,b)=a$ ,此时有唯一的解 : $x=1,y=0$; 2.当$a\times b\not= 0$ 时 , (设 $x1,y1$是满足如上情况的一组合法的解 ) 根据欧几里得定理 : $ \gcd(a,b) = \gcd(b,a\% b)$ , 可知: $\large \underline{ax + by }= gcd(a,b) = gcd(b,a\% b)=\underline{b {x1} + (a\% b) y 1}$ **而:** $a\% b = a-\lfloor \dfrac{a}{b}\rfloor \times b$ **则:** 原等式可转化为: ①. $ax + by = bx1 + (a-\lfloor \dfrac{a}{b}\rfloor \times b)y1$ ②. $ax + by = bx1 + ay1 -\lfloor \dfrac{a}{b}\rfloor by 1$ ③. $ax + by = ay1 +b(x1-\lfloor \dfrac{a}{b}\rfloor y 1)$ **由③,可得:** $x = y1$ $y=x1- \lfloor\dfrac{a}{b}\rfloor y1 $ **这样** , 就可以得到 $ax+by = c$ 的一组合法解 方程其他整数解 $xi,yi$ 满足 : $xi = x + \dfrac{b}{gcd(a,b)} \times t $ $yi = y - \dfrac{a}{gcd(a,b)} \times t $ 其中 , $t \in Z$ ------------ - 代码实现 要想写一个求解 $ax + by = \gcd(a,b)$ 的程序 通过以上的证明 , 显然 , 可以通过递归实现 递归边界即 : 当$b=0 $时 , $\gcd(a,b)=a$ , 此时有唯一的解 : $x=1,y=0$; 代码: ```cpp int exgcd(int a,int b,int d,int &x,int &y) { if(!b) { x=1 , y=0; return a; } d=exgcd(b,a % b,x,y); int tmp=x; x=y , y=tmp-a/b*y; } ``` ------------ - ### 应用: 1. 求解不定方程; 2. 求解同余方程; 3. 求解模的逆元; 4. 求解同余方程组 (扩展中国剩余定理) - 求解不定方程: 对于不定方程 : $ ax + by = c $ : 根据 扩展欧几里得 , **可知 :** 不定方程 $ax + by = \gcd(a,b)$ , 有无数组解 $x,y$. **则有 :** 1. 若$ c\% \gcd(a,b) \not= 0 $ , 则原方程无解。 2. 若$c \% \gcd(a,b) = 0$ : 设 $d = \gcd(a,b)$ , **则原方程可转化为 :** $ a\times (x\times \dfrac{d}{c}) + b\times (y\times \dfrac{d}{c}) =d (= c\times \dfrac{d}{c})$ 换元,使 $x1=(x\times \dfrac{d}{c})$ , $y1=(y\times \dfrac{d}{c})$; 得到方程: $ax1 + by1 = d$ 解方程: $ax1 + by1 = d$ , 有无数组解 $x1,y1$, 求解出 $x1,y1$ 后 , **再转化:** $x=x1 \times \dfrac{c}{d}$ , $y=y1 \times \dfrac{c}{d}$ 即可得到原方程 $ax + by = c$ 的解 - 求解同余方程: [P1082 同余方程](https://www.luogu.org/problemnew/show/P1082) 对于同余方程 : $ax \equiv c\pmod b$ , 可以转化为 : $ax \%b = c\% b$ **则有:** $ ax + nb = c + mb $ , $(m,n \in Z)$ $ax+(n-m)b=c$ 设 $y = n - m$ 则推出 $ ax +yb = c $ 就转化成了 不定方程 求解的问题。 求得 $x,y$ 后 , 所得的 $x$ , 即原方程 : $ax \equiv c\pmod b$ 的解 这样求出来的 $x$ 必然满足方程,但可能不是最小的 正整数 解 若要获得最小正整数解,需要再加这样一步操作: ```cpp x = (x+b)%b; ``` - 求解模的逆元: [P3811 【模板】乘法逆元](https://www.luogu.org/problemnew/show/P3811) ~~(但是此题卡扩欧)~~ **也适用于 模数不为质数的情况** 求解 $x \times inv(x) \equiv 1\pmod p$ 其中 $x,p$ 都是已知的。 有没有很眼熟 ? 换元 , 使 $a=x , x=inv(x) , c=1$ 原方程变为 : $ax \equiv 1 \pmod p$ 这就是一个 未知数为 $inv(x)$ , 方程右侧的 $c=1$ 的同余方程 , 求 $inv(x)$ 的值 , 解出此同余方程即可。 代码实现: ```cpp #include<cstdio> int exgcd(int a,int b,int &x,int &y) { if(!b) return x=1,y=0,a; int d=exgcd(b,a%b,x,y) ; int tmp=x; x=y , y=tmp-(a/b)*y; return d; } signed main() { int x,y,a,p; scanf("%d%d",&a,&p); exgcd(a,p,x,y); x=(x%p+p)%p; printf("%d",x); } ``` 如果想学习其他几种求解乘法逆元的方法 可以参考这篇博客: [题解 P3811 【模板】乘法逆元】-地靈殿-洛谷博客](https://www.luogu.org/blog/koishikoishi/solution-p3811) --- - 求解同余方程组 (扩展中国剩余定理) ~~咕了好久终于来更新了~~ [P4777 【模板】扩展中国剩余定理(EXCRT)](https://www.luogu.org/problemnew/show/P4777) - ##### 要解如下的同余方程组 : $\begin{cases}x \equiv a_1\pmod {b_1}\\x \equiv a_2\pmod {b_2}\\......\\x \equiv a_n\pmod {b_n}\\\end{cases}$ 其中 , $a_i,b_i$为非负整数 , $b_1,b_2,...,b_n$ 不一定互质 - ##### 求解: 使用 $exgcd$ , 进行同余方程的合并 . 假设已经求出了前 $k-1$ 个方程的解 $\large x_{k-1}$ 设 $\large M=lcm_{i=1}^{k-1} bi$ , 即 $M$ 为前 $k-1$ 个模数 $b$ 的最小公倍数 **则 :** 对于前 $k-1$个方程, 都满足$\large x_{k-1}+tM\equiv a_i\pmod {b_i}\ \ (t\in Z)$ 即 : 前 $k-1$ 个方程 , 通解为 $\large x_{k-1}+tM\ \ (t\in Z)$ 欲求得第 $k$ 个方程的解 , 并且将求得的解 , 也满足前 $k-1$ 个方程 **则 :** 需要使第 $k$ 个方程的解 , 为前 $k-1$ 的方程的通解的同时 , 也满足第 $k$ 个方程的条件 。 设 : 第$k$ 个方程的解 $\large x_k = x_{k-1}+tM\ \ (t\in Z)$ 将此解代入第 $k$ 个方程中 , 可得 : $\large x_{k-1}+tM\equiv a_k\pmod{b_k}$ 即 : $\large tM\equiv a_k-x_{k-1}\pmod{b_k}$ 其中 : $\large M,a_k,x_{k-1},b_k$ 都是已知的 。 使用 $exgcd$ 解出此同余方程 , 可以得到 $t$ 的值 。 将 $t$ 的值代回 $\large x_k = x_{k-1}+tM\ \ (t\in Z)$ ,就可得到$x_k$的值 进行 $k$ 次上述操作后 ,便可得到 方程组的解 。 贴一下代码: $ps$ : 原题数据较大,使用了快速乘取余 ```cpp #include<cstdio> using namespace std; typedef long long ll; ll n; ll a[100010],b[100010]; ll mul(ll A,ll B,ll mod) //快速乘取余 模板 { ll ans=0; while(B>0) { if(B & 1) ans=(ans+A%mod)%mod; A=(A+A)%mod; B>>=1; } return ans; } ll exgcd(ll A,ll B,ll &x,ll &y) //扩展欧几里得 模板 { if(!B) { x=1,y=0; return A; } ll d=exgcd(B,A%B,x,y); ll tmp=x; x=y , y=tmp-A/B*y; return d; } ll lcm(ll A,ll B) //求最小公倍数 { ll xxx,yyy; ll g=exgcd(A,B,xxx,yyy); return (A/g*B); } ll excrt() //重点:求解同余方程组 { ll x,y; ll M=b[1],ans=a[1]; //赋初值 //M为前k-1个数的最小公倍数,ans为前k-1个方程的通解 for(int i=2;i<=n;i++) { ll A=M,B=b[i]; ll C=(a[i]-ans%B+B)%B; //代表同余方程 ax≡c(mod b) 中a,b,c ll g=exgcd(A,B,x,y); //求得A,B的最大公约数,与同余方程ax≡gcd(a,b)(mod b)的解, if(C%g) return -1; //无解的情况 x=mul(x,C/g,B); //求得x的值,x即t ans+=x*M; //获得前k个方程的通解 M=lcm(M,B); //更改M的值 ans=(ans%M+M)%M; } return ans; } int main() { scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld%lld",&b[i],&a[i]); ll ans=excrt(); printf("%lld",ans); } ``` ------------ 欢迎转载 , 转载请联系作者 , 并注明出处 ~~(虽然这么个小破文肯定不会有人转载的)~~