博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[数论]Gcd/ExGcd欧几里得学习笔记
阅读量:5068 次
发布时间:2019-06-12

本文共 3523 字,大约阅读时间需要 11 分钟。

\(Q\):什么是\(GCD\)?

  • \(GCD\)

\(GCD\),即最大公约数(\(Greatest\ Common\ Divisor\)

对于两个自然数\(a,b\),定义\(GCD(a,b)\)\(a,b\)所有公共约数中最大的一个,即\(GCD(a,b)=\max\{x\in N^*,x|a\)\(x|b\}\)

然后是关于\(GCD\)的算法即其扩展


\(Part1\) 欧几里得算法

\(Q\):这个算法有什么用?

此算法可以在\(log\)级别里求出两个数\(a,b\)\(GCD\)

  • 欧几里得算法

对于\(a,b\),设它们的\(GCD\)\(d\)

则有:\(d|a\)\(d|b\)

\(a=k*{}b+r(k=\left\lfloor\frac{a}{b}\right\rfloor,r=a\mod b)\)

则:\(d|(a-k*{}b)\),即\(d|r\)

所以\(GCD(a,b)=GCD(b,r)=GCD(b,a\mod b)\)

最后递归求解,可在\(O(log_2a)\)内得解。

时间复杂度 \(O(log_2a)\)

空间复杂度 \(O(log_2a)\)(递归栈)

实际复杂度一般到不了此上界。

代码:

//求GCD(a,b)#include 
int GCD(int a,int b){ return b?GCD(b,a%b):a; //当b为0时,GCD(a,0)=a,充当递归边界。}int main(){ int a,b; scanf("%d%d",&a,&b); printf("%d\n",GCD(a,b)); return 0;}

\(Part2\) 扩展欧几里得

\(Q\):这个奇怪的算法又是什么啊?

首先,先来看一个不定方程:

\[ax+by=c\]

扩展欧几里得就是用来求此方程的不定解\((x,y)\)的。

准备知识:

  • \(Bezout\)定理

对于两个整数\(a,b\)存在一对整数\(x,y\),满足\(ax+by=GCD(a,b)\)

证明:

在调用欧几里得算法时,当\(b=0\),显然有\(x=1,y=0\)满足定理。

\(b\not= 0\)时,若已经求得,\(x,y\),使得

\[bx+(a\mod b)y=GCD(b,a\mod b)\]

\[bx+(a-b\left\lfloor\frac{a}{b}\right\rfloor)y=GCD(b,a\mod b)\]

\[ay+b(x-\left\lfloor\frac{a}{b}\right\rfloor y)=GCD(b,a\mod b)\]

\(x'=y,y'=x-\left\lfloor\frac{a}{b}\right\rfloor y\),则有

\[ax'+by'=GCD(b,a\mod b)=GCD(a,b)\]

利用数学归纳法,知道\(Bezout\)成立。

同时,我们可以利用此定理求出一组\(ax+by=GCD(a,b)\)的解。

时间复杂度 \(O(log_2a)\)

空间复杂度 \(O(log_2a)\)

代码:

//求x,y使得ax+by=GCD(a,b),同时得到GCD(a,b)#include 
int ExGCD(int a,int b,int &x,int &y){ if(!b){x=1,y=0;return a;}//递归边界 int GCD=ExGCD(b,a%b,x,y); int Tmp=x; x=y,y=Tmp-a/b*y; return GCD;}int main(){ int a,b,GCD,x,y; scanf("%d%d",&a,&b); GCD=ExGCD(a,b,x,y); printf("%d %d %d\n",GCD,x,y); return 0;}

接着回到正题:对于方程\(ax+by=c\),它有解仅当\(GCD(a,b)|c\)

证明?不会,记住就行,毕竟显然。

接着,求出方程\(ax+by=GCD(a,b)\)的一组解,则:

\[ax+by=GCD(a,b)\]

\[\frac{c}{GCD(a,b)}*{}(ax+by)=c\]

\[a*\frac{cx}{GCD(a,b)}+b*\frac{cy}{GCD(a,b)}=c\]

于是就有了一组解:\(x'=\frac{cx}{GCD(a,b)},y'=\frac{cy}{GCD(a,b)}\)(对\(x,y\)同时乘上\(\frac{c}{GCD(a,b)}\))

于是问题得解。

时间复杂度 \(O(log_2a)\)

空间复杂度 \(O(log_2a)\)

代码:

//求x,y使得ax+by=c,同时得到GCD(a,b)#include 
int ExGCD(int a,int b,int &x,int &y){ if(!b){x=1,y=0;return a;}//递归边界 int GCD=ExGCD(b,a%b,x,y); int Tmp=x; x=y; y=Tmp-a/b*y; return GCD;}int main(){ int a,b,c,GCD,x,y; scanf("%d%d%d",&a,&b,&c); GCD=ExGCD(a,b,x,y); if(c%GCD)return puts("Orz I cannot find it!"),0;//无解 int d=c/GCD; printf("%d %d %d\n",GCD,x*d,y*d); return 0;}

关于通解以及\(x\)最小正整数解。

\(d=GCD(a,b)\)

\(x_0,y_0\)\(ax+by=GCD(a,b)\)的一组特解,

\(x=x_0+km,y=y_0+kn(k\in \mathbb{Z})\)为方程的通解表示(k为任意整数),

则:

\[ax+by=ax_0+by_0\]

\[a(x_0+km)+b(y_0+kn)=ax_0+by_0\]

\[am+bn=0\]

显然,当\(m=-b,n=a\)时等式成立。

又因为要把\(m,n\)比例降到最小,所以同时除去\(GCD\)

最后的通解表示为:

\[x=x_0-k\frac{b}{d},y=y_0+k\frac{a}{d}(k\in \mathbb{Z})\]

同理,对于方程\(ax+by=c\)的通解为:

\[x=\frac{c}{d}x_0-k\frac{b}{d},y=\frac{c}{d}y_0+k\frac{a}{d}(k\in \mathbb{Z})\]

所以求\(x\)的最小整数解只需要将\(x\mod \frac{b}{d}\)再推出\(y\)即可。

时间复杂度 \(O(log_2a)\)

空间复杂度 \(O(log_2a)\)

代码:

//求ax+by=c的x最小正整数解。#include 
int ExGCD(int a,int b,int &x,int &y){ if(!b){x=1,y=0;return a;}//递归边界 int GCD=ExGCD(b,a%b,x,y); int Tmp=x; x=y; y=Tmp-a/b*y; return GCD;}int main(){ int a,b,c,d,x,y; scanf("%d%d%d",&a,&b,&c); d=ExGCD(a,b,x,y); if(c%d)return puts("Orz I cannot find it!"),0;//无解 x*=c/d,y*=c/d; int f=b/d; x=(x%f+f)%f; y=(c-a*x)/b; printf("%d %d\n",x,y);//x最小正整数解。 return 0;}

所有性质证明到此结束。


欧几里得是个好东西,然而我不会用

数论博大精深,不能就此止步,还要继续探索。

祝自己\(++OI::RP\)

转载于:https://www.cnblogs.com/LanrTabe/p/10370627.html

你可能感兴趣的文章
软件测试系列--通用测试用例写作
查看>>
SQL语句题
查看>>
Android消息机制
查看>>
iOS应用支持IPV6,就那点事儿
查看>>
mysql命令行导入和导出数据
查看>>
css中span元素的width属性无效果原因及多种解决方案
查看>>
解决IIS6.0 无法访问
查看>>
JQuery-UI Dialog下使用服务器端按钮失效
查看>>
Python 前端 js基础
查看>>
HTML5程序设计--SVG
查看>>
洛谷P3328(bzoj 4085)毒瘤线段树
查看>>
格式化输出数字和时间
查看>>
页面中公用的全选按钮,单选按钮组件的编写
查看>>
判断文本框输入的文字长度
查看>>
java笔记--用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程
查看>>
Scaling Pinterest - From 0 To 10s Of Billions Of Page Views A Month In Two Years
查看>>
SelectSort 选择排序
查看>>
关于android 加载https网页的问题
查看>>
BZOJ 1047 HAOI2007 理想的正方形 单调队列
查看>>
各种语言推断是否是手机设备
查看>>