gcd及扩展gcd可以用来求两个数的最大公因数,扩展gcd甚至可以用来求一次不定方程ax+by=c的解

 

辗转相除法与gcd


假设有两个数a与b,现在要求a与b的最大公因数,我们可以设

  a=b*q+p

  如果a是与b的最大公约数是gcd(a,b),那么b与p的最大公约数也是gcd(a,b)

  gcd(a,b)=gcd(b,p)=gcd(b,a%b),然后我们令a=b,b=a%b,然后再进行以上步骤

  以此类推,a与b的值会越来越小,直到某一时刻a变成了b的倍数,使得a%b=0,但是后来赋值使得a=b,b=a%b,所以等到b=0的时候,a的值就是原来a与b的最大公约数了。

证明在循环过程中一定存在某一时刻,使得a为b的倍数:

  由于当a为正数(负数)时,a%b的值一定是正数(负数),也就是说,当b的值不断减小,最多也就减小到1(-1),而此时a一定是b的倍数。当然,不一定只有当b减小到1(-1)时,才会出现a%b=0,只要当b等于原来a和b最大公约数的时候,就一定会发生a%b=0

  1. long long getGcd(long long _a,long long _b){
  2. ) return _a;
  3. else return getGcd(_b,_a%_b);
  4. }

gcd


裴蜀定理


  ax + by = m
  有解当且仅当m是gcd(a,b)的倍数。裴蜀等式有解时必然有无穷多个整数解,每组解x、y都称为裴蜀数,可用辗转相除法求得。

重要推论:

  a,b互质的充要条件是存在整数x,y使ax+by=1.

特别的:

  方程 ax + by = 1 有解当且仅当整数a和b互素。


扩展gcd


前言

  扩展gcd是在普通的gcd上做了一些升级,扩展gcd不仅可以求出a和b最大公约数,还可以求出ax+by=gcd(a,b)的一组解,进而可以求出ax+by=gcd(a,b)以及ax+by=c的解集

求ax+by=gcd(a,b)的一组解(扩展gcd)

通过gcd可以知道

  gcd(a,b)=gcd(b,a%b)

又因为

  ax+by=gcd(a,b)

由普通gcd,可以通过a=b,b=a%b代换得

  bx+a%b*y=gcd(b,a%b)

因此

  ax+by=bx+a%b*y=bx+(a-[a/b]*b)*y=bx+ay-[a/b]*b*y=ay+(x-[a/b]*b*y)

可以得到x与y的更新式

  x'=y,y'=x-[a/b]*b

注意一点,如果当b=0时,那么ax+by=gcd(a,b)=a,此时xy的更新式为

  x'=1,y'=0;

 

求ax+by=c的一组解

  通过扩展gcd,可以得到ax'+by'=gcd(a,b)的解x'与y',如果ax+by=c存在整数解,根据裴蜀定理可知一定满足条件c是gcd(a,b)的倍数

因此,将等式左右两边乘c/gcd(a,b),得到:

  ax'*c/gcd(a,b)+by'*gcd(a,b)=ax+by=c

于是,得到了ax+by=c的解为:x=x'*c/gcd(a,b),y=y'*c/gcd(a,b),其中x'和y'是通过扩展gcd求出的一组解

ax+by=c及ax+by=gcd(a,b)的解集表示

  假设我们得出ax+by=c一组解x与y,如果x每减去一个t(t为常数),那么y至少必须加上一个(a'*t/b'其中a'=a/gcd(a,b),b'=b/gcd(a,b))),才能使等式两边成立,即

  a(x-t)+b(y+a'*t/b')=ax+by=c

  由于我们需要变换后的x和y仍然是整数,由于t已经是整数,即x-t也一定是整数,现在只需考虑a'*t/b'是否为整数,由于gcd(a',b')=1,即a'一定不是b'的倍数,故必须令t=t*b'(即t必须是b'的倍数),才使得a'*t/b'为整数,即解集为:

  x=x-t*b/gcd(a,b),y=y+t*a/gcd(a,b),t为任意整数

特别的,当gcd(a,b)=1,解集为:x=x-t*b,y=y+t*a

求ax+by=c的非负整数解(important)

  非负整数解:x与y都为非负数,且x与y都与0比较接近的解

ps:令gcd(a,b)=gcd,以下计算之前应该先把a=a/gcd,b=b/gcd,因为解集中x是加减b/gcd,同理y,这样可以防止得到的解不是最小解。

考虑三种情况:

  (1).当a,b>0,c>0

  这种情况可能存在x与y都为非负整数的解,且当x为x解集中最小的非负整数时,如果此时对应的y为非负整数,那么就存在一组最小非负整数解;如果此时y为负数,那么就一定不存在最小非负整数解。

此时

  x=(x%b+b)%b,y=(c-a*gcd*x)/(b*gcd)

但是此时x的确的相对于y来说更接近0,但是y可能并不是很接近0,比如解50x+y=100,用这种方法解出来的解为x=0,y=100,相对于x=2,y=0来讲并不是最优解,此时让y更接近0才获得更好的答案,因此可以优化解,此时

  当a>=b时,y=(y%a+a)%a,x=(c-b*gcd*y)/(a*gcd);

  当a<b时,x=(x%b+b)%b,y=(c-a*gcd*x)/(gcd*b);

这样以来,就可以通过a与b的大小,来判断哪个未知数接近0可以获得更完美的解

  (2).当a,b>0,c<0

  这种情况一定不会出现最小非负整数解,但是为了让解更加接近0,因为当c>0和当c<0是一种对称情况,如果存在一组x与y,是得当a,b>0,c>0时的最小非负整数解,那么-x与-y就一定是c<0时的最接近0的解。

此时

  当a>=b时,y=-(y%a+a)%a,x=(c-b*gcd*y)/(a*gcd);

  当a<b时,x=-(x%b+b)%b,y=(c-a*gcd*x)/(b*gcd);

  (3).当a>0,b<0   或   a<0,b>0

  此时方程可以看成ax-b'y=c(a*b'>0),这时一定存在d与e,使得d-e=c,即ax-b'y=d-e,可以变形为e+ax=d+b'y

这个式子可以看做:

  sum1=e+ax,sum2=d+b'y,sum1等于e加上x个a,sum2等于d加上y个b',当sum1与sum2第一次相同(由于a*b'>0,当a与b同小于0时,第一次相同的时sum1=sum=sum,sum一定小于e和d,同理a与b'大于0)时,x与y的值为多少?

  当d>e  =>  c>0时,当y>0时,x一定大于0,此时让y取解集中靠近0非负解,得到的x与y一定是最小非负解

此时:x=x%b<0?x%b+(b<0?-b:b):x%b,y=(c-a*gcd*x)/(b*gcd);

  当d<e  =>  c<0时,当x>0时,y一定大于0,此时让x取解集中靠近0非负解,得到的x与y一定是最小非负解

此时:y=y%a<0?y%a+(a<0?-a:a):y%a,x=(c-b*gcd*y)/(a*gcd);


  (当然,这个情况的求最小解的方法公式也可以得到其他情况的最小解)


总结代码


1.a与b的最大公因数

2.求ax+by=c的某一个解

3.求ax+by=c的最小正整数解(如果不存在则求靠近0,0的解)

  1. #include <iostream>
  2. using namespace std;
  3. */long long getGcd(long long _a,long long _b){
  4. ) return _a;
  5. else return getGcd(_b,_a%_b);
  6. }
  7. */long long getExgcd(long long _a,long long _b,long long &_x,long long &_y){
  8. ){
  9. _x=,_y=;
  10. return _a;
  11. }
  12. long long _gcd=getExgcd(_b,_a%_b,_x,_y);
  13. long long _rx=_x;
  14. _x=_y;
  15. _y=_rx-_a/_b*_y;
  16. return _gcd;
  17. }
  18. */long long getAnyCalc(long long _a,long long _b,long long _c,long long &_x,long long &_y){
  19. long long _gcd=getExgcd(_a,_b,_x,_y);
  20. ;
  21. long long _transit=_c/_gcd;
  22. _x*=_transit;_y*=_transit;
  23. return _gcd;
  24. }
  25. */long long getUpCalc(long long _a,long long _b,long long _c,long long &_x,long long &_y){
  26. long long _gcd=getExgcd(_a,_b,_x,_y);
  27. ;
  28. long long _transit=_c/_gcd;
  29. _x*=_transit;_y*=_transit;
  30. long long __a=_a,__b=_b;
  31. _a/=_gcd;_b/=_gcd;
  32. _x=_x%_b<?_x%_b+(_b<?-_b:_b):_x%_b;
  33. _y=_y%_a<?_y%_a+(_a<?-_a:_a):_y%_a;
  34. ) _y=(_c-__a*_x)/__b;
  35. else _x=(_c-__b*_y)/__a;
  36. return _gcd;
  37. }
  38. int main(){
  39. getGcd(
  40. getAnyCalc(long long a,long long b,long long c,long long x,long long y)//2,3
  41. getUpCalc(long long a,long long b,long long c,long long x,long long y)//2,4
  42. }

三小问代码

使用说明:函数getGcd(long long a,long long b)求a与b的最大公约数(需要1号函数

     函数getAnyCalc(long long a,long long b,long long c,long long x,long long y)求ax+by=c的某一个解(不存在解返回-1,存在返回gcd(a,b),解x与y传的是引用)(需要2,3号函数

     函数getUpCalc(long long a,long long b,long long c,long long x,long long y)求ax+by=c的最小非负整数解(不存在解返回-1,存在解且不存在最小非负整数解则得到的解为靠近(0,0)的解且返回的是gcd(a,b))(需要2,4号函数


例题


1.江西财经大学第二届程序设计竞赛同步赛----H-大时钟:https://blog.csdn.net/weixin_43702895/article/details/89422929

学习:数学----gcd及扩展gcd的更多相关文章

  1. GCD和扩展GCD

    gcd(a, b)用于求解自然数a,b的最大公约数 int gcd(int a, int b) { ) return a; return gcd(b, a%b); } extgcd(a, b, x, ...

  2. 详解扩展欧几里得算法(扩展GCD)

    浅谈扩展欧几里得(扩展GCD)算法 本篇随笔讲解信息学奥林匹克竞赛中数论部分的扩展欧几里得算法.为了更好的阅读本篇随笔,读者最好拥有不低于初中二年级(这是经过慎重考虑所评定的等级)的数学素养.并且已经 ...

  3. UESTC 288 青蛙的约会 扩展GCD

    设两只青蛙跳了t步,则此时A的坐标:x+mt,B的坐标:y+nt.要使的他们在同一点,则要满足: x+mt - (y+nt) = kL (p是整数) 化成: (n-m)t + kL = x-y (L ...

  4. Poj 1061 青蛙的约会(扩展GCD)

    题目链接:http://poj.org/problem?id=1061 解题报告:两只青蛙在地球的同一条纬度线上,选取一个点位坐标轴原点,所以现在他们都在同一个首尾相连的坐标轴上,那么他们现在的位置分 ...

  5. poj 1061 青蛙的约会(扩展gcd)

    题目链接 题意:两只青蛙从数轴正方向跑,给出各自所在位置, 和数轴长度,和各自一次跳跃的步数,问最少多少步能相遇. 分析:(x+m*t) - (y+n*t) = p * L;(t是跳的次数,L是a青蛙 ...

  6. 2014年百度之星程序设计大赛 - 初赛(第一轮) hdu Grids (卡特兰数 大数除法取余 扩展gcd)

    题目链接 分析:打表以后就能发现时卡特兰数, 但是有除法取余. f[i] = f[i-1]*(4*i - 2)/(i+1); 看了一下网上的题解,照着题解写了下面的代码,不过还是不明白,为什么用扩展g ...

  7. BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS

    BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS 题意: 你被要求设计一个计算器完成以下三项任务: 1.给定y,z,p,计算Y^Z Mod P 的值: 2.给定y,z,p, ...

  8. 【learning】 扩展欧几里得算法(扩展gcd)和乘法逆元

    有这样的问题: 给你两个整数数$(a,b)$,问你整数$x$和$y$分别取多少时,有$ax+by=gcd(x,y)$,其中$gcd(x,y)$表示$x$和$y$的最大公约数. 数据范围$a,b≤10^ ...

  9. gcd,扩展欧几里得,中国剩余定理

    1.gcd: int gcd(int a,int b){ ?a:gcd(b,a%b); } 2.中国剩余定理: 题目:学生A依次给n个整数a[],学生B相应给n个正整数m[]且两两互素,老师提出问题: ...

随机推荐

  1. [HDU5290]Bombing plan

    vjudge sol 树DP. 首先把模型转换成:每个点可以控制与它距离不超过\(w_i\)的点,先要求选出数量最少的点控制所有点. 设\(f[i][-100...100]\)表示\(i\)号点向上还 ...

  2. Java Modifiers

    Private means this could only be seen within this class. Protected means "package private" ...

  3. POJ2442:Sequence

    浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html 题目传送门:http://poj.org/problem?id=2442 我们先简化题意,假设只有两 ...

  4. 堆排序的JavaScript实现

    思想 把数组当做二叉树来排序: 索引0是树的根节点: 除根节点外,索引为N的节点的父节点索引是(N-1)/2: 索引为N的节点的左子节点索引是 2*N+1; 索引为N的节点的右子节点索引是 2*N+2 ...

  5. SpringMvc之参数绑定注解详解之四

    简介: @RequestBody 作用: i) 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对 ...

  6. AjaxMethod的使用

        AjaxMethod的使用 使用AjaxMethod要满足一下几点: 1.如果还没有ajax.dll文件,就先下载一个来 2.将ajax.dll添加到项目引用中:在VS的解决方案资源管理器中右 ...

  7. 关于导入excel报错的处理(xls,xlsx)

    关于导入excel报错的处理(xls,xlsx) 最近在做一个将excel导入到dataGriview中的小功能在做的过程中遇到以下问题: 链接excel的链接串是这样写的 string strCon ...

  8. String/ StringBuilder/ StringBuffer

    1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...

  9. 关于cin

    今天同学调试一个简单的程序的时候发现了问题,我们两个讨论的时候弄出了好多乐子 #include <iostream> using namespace std; int main() { ; ...

  10. 基于OpenCV依次读取文件夹下的所有图像文件

    //编程环境:VS2008+OpenCV1.1, //本程序首先挨个读取F://my face database//OnlyFace文件夹下的所有图 像 文件,之后,在项目文件夹下 //建立一 个名为 ...