拓展欧几里得算法

  • 欧几里得算法简介
  • 拓展欧几里得算法简介
    • 【递归方法:倒序带入法】
    • 【递归代码】
    • 【递推方法:滚动变量记录法】
    • 【递推代码】
  • 应用:如何解 ax+by=c
    • 测试代码

欧几里得算法简介

  • 大部分参考与查阅:《初等数论及其基本应用》原书第六版。
  • 辗转相除法
    令整数 r0=a,r1=br_0=a,r_1=br0​=a,r1​=b,满足 a≥b>0a\ge b>0a≥b>0,连续做除法得到:
    rj=rj+1qj+1+rj+2(j=0ton−2),rn+1=0r_j=r_{j+1}q_{j+1}+r_{j+2}(j=0\ to\ n-2),r_{n+1}=0rj​=rj+1​qj+1​+rj+2​(j=0 to n−2),rn+1​=0
    那么 (a,b)= rnr_nrn​
  • 例如对于 (252,198)的例子:
j rjr_jrj​ rj+1r_{j+1}rj+1​ qj+1q_{j+1}qj+1​ rj+2r_{j+2}rj+2​
0 252 198 1 54
1 198 54 3 36
2 54 36 1 18
3 36 18 2 0
  • 算法的时间复杂度(拉梅定律): O(5log⁡10b)O(5\log_{10} b)O(5log10​b)

拓展欧几里得算法简介

  • 在欧几里得算法的基础上,我们记录出一些数值为了
  • 用线性组合来表示最大公因子
  • 比如,(252,198)=18(252,198)=18(252,198)=18,但是我想知道 252s+198t=18252s+198t=18252s+198t=18,其中两个系数该怎么取。

【递归方法:倒序带入法】

见上倒数第二步,18=54−1∗3618=54-1*3618=54−1∗36
前一步为 36=198−3∗5436=198-3*5436=198−3∗54
带入得到 18=54−1∗(198−3∗54)=4∗54−1∗19818=54-1*(198-3*54)=4*54-1*19818=54−1∗(198−3∗54)=4∗54−1∗198
⋯\cdots⋯

【算法描述】:
原理:更新 x、yx、yx、y,使得 rj∗x+rj+1∗y=(a,b)r_j*x+r_{j+1}*y=(a,b)rj​∗x+rj+1​∗y=(a,b)恒成立。

步骤:首先跑一边欧几里得算法,接下来逆序计算。
首先,rn=(a,b),rn+1=0r_n=(a,b),r_{n+1}=0rn​=(a,b),rn+1​=0
对于特定的 jjj ,如果已经求得 (a,b)=srj+trj−1(a,b)=sr_j+tr_{j-1}(a,b)=srj​+trj−1​
那么,因为 rj=rj+1qj+1+rj+2(j=0ton−2),rn+1=0r_j=r_{j+1}q_{j+1}+r_{j+2}(j=0\ to\ n-2),r_{n+1}=0rj​=rj+1​qj+1​+rj+2​(j=0 to n−2),rn+1​=0
等式变一变,我们有:
rj=rj−2−rj−1qj−1r_j=r_{j-2}-r_{j-1}q_{j-1}rj​=rj−2​−rj−1​qj−1​
带入得到:
(a,b)=s(rj−2−rj−1qj−1)+trj−1=(t−sqj−1)rj−1+srj−2\begin{aligned}(a,b)&=s(r_{j-2}-r_{j-1}q_{j-1})+tr_{j-1}\\&=(t-sq_{j-1})r_{j-1}+sr_{j-2}\end{aligned}(a,b)​=s(rj−2​−rj−1​qj−1​)+trj−1​=(t−sqj−1​)rj−1​+srj−2​​
如果仔细看一下式子,便可以发现:

经过一次变换之后,
sss变成(t−sqj−1)(t-sq_{j-1})(t−sqj−1​)
ttt变成sss

经过多次变换之后,我们的 s、rs、rs、r的系数就可以从rn、rn+1r_n、r_{n+1}rn​、rn+1​ 变成 r0、r1r_0、r_1r0​、r1​,也就是我们想要得到的线性组合的两个系数了。

【递归代码】

ll ex_gcd(ll a,ll b,ll& x,ll& y) { if(b==0) {x=1;y=0;return a;}ll g=ex_gcd(b,a % b,x,y);ll tmp = x;x = y; y = tmp - a / b * y;return g;
}

【递推方法:滚动变量记录法】

原理:我们保持 rj=sja+tjbr_j=s_ja+t_jbrj​=sj​a+tj​b 其恒成立

首先,我们递归定义一下:

(a,b)=sna+tnb(a,b)=s_na+t_nb(a,b)=sn​a+tn​b

s0=1,t0=0s_0=1,t_0=0s0​=1,t0​=0
s1=0,t1=1s_1=0,t_1=1s1​=0,t1​=1

∀j≥2sj=sj−2−qj−1sj−1tj=tj−2−qj−1tj−1\forall\ j\ge 2\\s_j=s_{j-2}-q_{j-1}s_{j-1}\\t_j=t_{j-2}-q_{j-1}t_{j-1}∀ j≥2sj​=sj−2​−qj−1​sj−1​tj​=tj−2​−qj−1​tj−1​

证明(第二数归,略)

【递推代码】

ll ex_gcd2(ll a,ll b,ll& s1,ll &t1) {s1 = 0;t1 = 1;ll s2 = 1,t2 = 0;ll q;bool fir = true;while(b){if(!fir){ll n1 = s2 - q * s1;ll n2 = t2 - q * t1;s2 = s1;s1 = n1;t2 = t1;t1 = n2;}if(b)q = a / b;ll tmp = a;a = b;b = tmp % b;fir = false;}return a;
}

应用:如何解 ax+by=c

【题目介绍】
a、b、ca、b、ca、b、c是已给出的整数。
我想求得一组整数解 x,yx,yx,y,满足 a∗x+b∗y=ca*x+b*y=ca∗x+b∗y=c

  • 首先,我们得到 g=(a,b)g=(a,b)g=(a,b),并且容易知道 g∣(ax+by)g|(ax+by)g∣(ax+by)
  • 换句话说,只有 g∣cg|cg∣c ,该方程才有解。
  • 并且,若 g∣cg|cg∣c,该方程有无穷多个解。

【常规解法】:

  1. 求出 g=(a,b)g=(a,b)g=(a,b)
  2. 若 g∤cg\nmid cg∤c,则该方程无解,直接跳出。否则有无穷多个解。
  3. 我们先求出 ax+by=gax+by=gax+by=g的解,然后方程两边同时乘以 cg,即可得到解\frac{c}{g},即可得到解gc​,即可得到解
  4. 解方程 ax+by=gax+by=gax+by=g ,首先得求得该方程的一个解,即求出 (a,b)(a,b)(a,b) 的线性组合,拓展欧几里得求出的两个系数即为其方程的一个解 x0,y0x_0,y_0x0​,y0​
  5. 方程 ax+by=gax+by=gax+by=g 的通解为 :
    {x=x0+kbgy=y0−kagk∈Z\begin{cases} x=x_0+k\frac{b}{g}\\ y=y_0-k\frac{a}{g}\\ \end{cases} \\k\in\mathbb{Z} {x=x0​+kgb​y=y0​−kga​​k∈Z
  6. 方程 ax+by=cax+by=cax+by=c 的通解为 :
    {x=x0cg+kbgy=y0cg−kagk∈Z\begin{cases} x=x_0\frac{c}{g}+k\frac{b}{g}\\ y=y_0\frac{c}{g}-k\frac{a}{g}\\ \end{cases} \\k\in\mathbb{Z} {x=x0​gc​+kgb​y=y0​gc​−kga​​k∈Z

测试代码

可以看递归方法是否满足 rj∗x+rj+1∗y=(a,b)r_j*x+r_{j+1}*y=(a,b)rj​∗x+rj+1​∗y=(a,b)恒成立。
可以看递推方法是否满足 rj=sja+tjbr_j=s_ja+t_jbrj​=sj​a+tj​b 其恒成立
可以看是否对于任意的整数 kkk 都满足 ax+by=cax+by=cax+by=c
只要在宏定义上面修改A、B、C的值即可。(可以看看 C∤(A,B)C\nmid(A,B)C∤(A,B)会发生什么)

/*_            __   __          _          _
| |           \ \ / /         | |        (_)
| |__  _   _   \ V /__ _ _ __ | |     ___ _
| '_ \| | | |   \ // _` | '_ \| |    / _ \ |
| |_) | |_| |   | | (_| | | | | |___|  __/ |
|_.__/ \__, |   \_/\__,_|_| |_\_____/\___|_|__/ ||___/
*/
#define ll long long
ll A = 252;
ll B = 198;
ll C = 36;
#define show(x) std::cerr << #x << " = " << x << std::endl
#define show2(x,y) std::cerr << #x << " = " << x << "   " << #y << " = " << y << std::endl
#define show3(x,y,z) std::cerr << #x << " = " << x << "   " << #y << " = " << y << "   " << #z << " = " << z << std::endl
#define show4(x,y,z,p) std::cerr << #x << " = " << x << "   " << #y << " = " << y << "   " << #z << " = " << z << "   " << #p << " = " << p << std::endl
ll ex_gcd(ll a,ll b,ll& x,ll& y) { if(b==0) { x=1;y=0;show2(x,y); return a; } ll g=ex_gcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-a/b*y; show3(x,y,a * x + b * y);return g; }ll ex_gcd2(ll a,ll b,ll& s1,ll &t1) {s1 = 0;t1 = 1;ll s2 = 1,t2 = 0;ll q;bool fir = true;while(b){if(!fir){ll n1 = s2 - q * s1;ll n2 = t2 - q * t1;s2 = s1;s1 = n1;t2 = t1;t1 = n2;show2(s1,t1);show(s1 * A + t1 * B);}if(b)q = a / b;ll tmp = a;a = b;b = tmp % b;fir = false;}return a;
}int main()
{ll x,y;cout << ex_gcd(A,B,x,y) << endl;show2(x,y);puts("----------");ll a,b;cout << ex_gcd2(A,B,a,b) << endl;show2(x,y);ll g = __gcd(A,B);for(int k = -5;k <= 5;++k){ll xx = x * C / g + k * B / g;ll yy = y * C / g - k * A / g;show2(xx,yy);cout << xx * A + yy * B << endl;}return 0;
}

【算法讲2:拓展欧几里得(简略讲)】求解 ax+by=c相关推荐

  1. 详细讲解【拓展欧几里得】

    exgcd(拓展欧几里得) 1.回顾辗转相除法求最大公倍数: (辗转相除法和下面所讲到的算法里面的m和n没什么关系可正可负 更没有大小关系的区分) 代码: #include<stdio.h> ...

  2. 拓展欧几里得定理的应用

    扩展欧几里得定理的运用 首先,先重复一下拓展欧几里得的内容: 对于不全为 0 的整数a.b,一定存在一组解 x,y,使得 ax + by == gcd(a,b) 先说一下这个定理的三个用处(但是小细节 ...

  3. A/B HDU - 1576 (逆元或拓展欧几里得或数学公式)多解法求大数结果

    题意:求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1). 思维:(1)逆元+扩展欧几里得算法:满足a*k≡1 (mo ...

  4. POJ1061青蛙的约会(拓展欧几里得)

    青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 146847 Accepted: 34169 Description ...

  5. 拓展欧几里得+例题~

    扩展欧几里德算法: 应用: ①求解不定方程 ②求解同余方程 ③求解模的逆元 看欧拉定理看吐了也还是有超级~~多的题目不会做,看的有晕又困!难受,看会别的压压惊~~希望拓展欧几里德的题目能对我稍稍稍稍稍 ...

  6. 关于欧几里得定理和拓展欧几里得定理的理解 续

    前言 在我大一刚开始ACM的时候,写过一篇关于欧几里得定理理解的博客,这几天因为再次用到欧几里得定理,所以又转回去看了看,感觉自己以前写的不是很清楚,所以决定再写一篇关于欧几里得定理以及拓展欧几里得定 ...

  7. poj1061-青蛙的约会(拓展欧几里得java)

    题目: 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚 ...

  8. 拓展欧几里得模板/求逆元模板(java)

    拓展欧几里得模板 参考:哈尔滨理工大学ACM培训资料汇编/ACM-ICPC培训资料汇编* 基本原理 :设 a 和 b 不全为 0,则存在整数 x,y 使得 xa yb=gcd(a,b)=c 对于辗转相 ...

  9. 杭电2669拓展欧几里得

    杭电2669 给a,b求Xa Yb = 1.如果没有则输出sorry. 可以通过拓展欧几里得指导Xa Yb = gcd(a,b). 不言而喻要判断gcd(a,b)是否等于1.如果不等于1,那么就是so ...

最新文章

  1. Python+selenium 自动化-切换窗口页签、切换iframe框架。确定页面是否包含iframe方法。
  2. 设计模式学习笔记(十)——Decorator装饰模式
  3. 实现AIDL接口的Binder连接池
  4. ubuntu20输入法qiehuan_UBUNTU 20 输入法问题
  5. CPU的向量化、多核技术、多路技术、众核技术
  6. 数据结构 2-0 线性表总结
  7. fork()成为负担,需要淘汰 | 极客头条
  8. 北京自动驾驶路测名单更新:蔚来和Pony.ai也获准上路了
  9. Q107:Linux系统下GDB对PBRT-V3进行debug
  10. 《中国人史纲》读书笔记:第二章 神话时代 第三章 传说时代
  11. 揭秘你不知道的京东管理体系!
  12. 直接sql 添加字段赋值
  13. 异常(Exception)
  14. FOC控制中Clark/iClark和Park/iPark变换及matpoltlib仿真
  15. 扫地机器人路径规划算法
  16. 圆柱模板价格计算器V1.0版本
  17. Spark的数据存储目录HDFS
  18. Python爬虫爬取百度贴吧的帖子
  19. 竞争定位、价值主张及企业市场细分
  20. Clear Case V7.0 官网下载地址

热门文章

  1. Android Studio中layout_gravity与gravity
  2. 前端水平垂直居中的方法
  3. 最新COS美女写真网站整站数据打包+附搭建教程/实测可用
  4. 【翻译】StreamDM:基于Spark Streaming的高级数据挖掘 StreamDM: Advanced Data Mining in Spark Streaming
  5. 人脸识别闸机python_Python 40行代码实现人脸识别功能
  6. [题解] Knights of Ni 骑士 C++
  7. wsappx是什么进程,可以关掉吗
  8. Android BLE(低功耗蓝牙)在Android不同版本的适配问题,华为Mate30扫描不到蓝牙模块
  9. 程序员,本周上新好书在等你
  10. SSH、telnet、远程桌面区别