zoukankan      html  css  js  c++  java
  • 欧几里得算法及其扩展学习笔记

    欧几里得算法

    在欧几里得著的《几何原本》里面,有用线段的划分来讲解这个数学方法的,这里我们从代数而不是几何上来讲,并且侧重于算法OI竞赛。

    欧几里得算法(gcdgcd),又称辗转相除法,可以用来快速计算两个整数的最大公约数,并有许多扩展应用。


    下面我们来看公式:
    gcd(n,m)=gcd(m,n mod m)gcd(n,m)=gcd(m,n m mod m)

    我们可以简单的证明一下这个公式的正确性:
    我们令g=gcd(n,m)g=gcd(n,m),那么显然gn,gmg|n,g|maba|b表示aabb的因子)。又因为n mod m=nm×nmn m mod m=n-m imes lfloorfrac{n}{m} floor,那么我们可以将n,mn,m写为n=k1g,m=k2gn=k_1g,m=k_2g,那么n mod m=nm×nm=k1gk2gk1gk2g=g(k1k2k1gk2g)n m mod m=n-m imes lfloorfrac{n}{m} floor=k_1g-k_2glfloorfrac{k_1g}{k_2g} floor=gleft(k_1-k_2leftlfloorfrac{k_1g}{k_2g} ight floor ight),而(k1k2k1gk2g)left(k_1-k_2leftlfloorfrac{k_1g}{k_2g} ight floor ight)肯定为整数,所以g(n mod m)g|(n m mod m),那么显然ggcd(m,n mod m)g|gcd(m,n m mod m),(因为ggn,mn,m的因子)。接下来我们令g^=gcd(m,n mod m)hat g=gcd(m,n m mod m),那么显然有g^ghat g|g,又因为前面我们可以得知gg^g|hat g,所以就有g=g^g=hat g,那么gcd(n,m)=gcd(m,n mod m)gcd(n,m)=gcd(m,n m mod m)

    所以代码就简单啦!
    递归边界为m=0m=0时,因为模数不能为0,所以此时就可以直接返回nn

    int gcd(int n,int m){
    	if(!m) return n;
    	else return gcd(m,n%m); 
    }//也可以用自带的__gcd(n,m);
    

    扩展欧几里得算法

    • 前置

    • 裴蜀定理(贝祖定理)

    内容:对于一个系数为整数(a,b,ca,b,c为整数)的二元一次方程ax+by=cax+by=c,若其存在整数解,当且仅当gcd(a,b)cgcd(a,b)|c
    用处:判断一个上述的二元一次方程是否有整数解。

    简单的证明:
    我们令g=gcd(a,b)g=gcd(a,b),同样的我们可以将a,ba,b写成a=k1g,b=k2ga=k_1g,b=k_2g,那么显然ax+by=g(k1x+k2y)ax+by=g(k_1x+k_2y),所以g(ax+by)g|(ax+by)

    所以当gcd(a,b)cgcd(a,b)|c时必然有整数解,下面我们将在扩展欧几里得算法讲解给出证明,及其整数解的求法。


    正题

    • Exgcd

    ax+by=cax+by=ccgcd(a,b)c|gcd(a,b)前提下是否一定有整数解呢?

    因为有了前提,所以我们可以将原式写成ax+by=kgcd(a,b)ax+by=kcdot gcd(a,b),由于kk为整数,那么如果ax+by=gcd(a,b)ax+by=gcd(a,b)有整数解,那么原式一定有整数解(倍数关系),那么只需证明并求出ax+by=gcd(a,b)ax+by=gcd(a,b)的一组特殊解(x1,y1)(x_1,y_1),然后所有的解都可以表示出来(原来的解就是现在解的kk倍)。

    所以现在我们只需证明ax+by=gcd(a,b)ax+by=gcd(a,b)有解即可。

    通过gcdgcd的递推式可知,我们如果的到如下式子的一组解:
    bx+(a mod b)y=gcd(b,a mod b)bx+(a m mod b)y=gcd(b,a m mod b)
    令解为(x1,y1)(x_1,y_1),那么就有如下推导:
    ax+by=bx1+(a mod b)y1ax+by=bx_1+(a m mod b)y_1
    =bx1+(aab×b)y1=bx_1+(a-leftlfloorfrac{a}{b} ight floor imes b)y_1
    =ay1+(x1aby1)b=ay_1+(x_1-leftlfloorfrac{a}{b} ight floor y_1)b
    一个小引理当ax+by=az+bkax+by=az+bk,必然x,yx,y有一组解为x=z,y=kx=z,y=k
    ax+by=ay1+(x1aby1)bax+by=ay_1+(x_1-leftlfloorfrac{a}{b} ight floor y_1)b
    所以有一组解为x=y1,y=x1aby1x=y_1,y=x_1-leftlfloorfrac{a}{b} ight floor y_1,而这个解显然一定会满足ax+by=gcd(a,b)ax+by=gcd(a,b)。所以我们不仅证明了它一定有解,还构造出了解的样子和求法。
    代码就是这样的:

    int exgcd(int a,int b,int &x,int &y){
    	if(!b){x=1;y=0;return a;}
    	else {int now=exgcd(b,a%b,y,x);y-=x*(a/b);return now;}
    }	
    

    递归边界显然就是当ax+by=gcd(a,b)ax+by=gcd(a,b)的时候,b=0b=0,显然gcd(a,b)gcd(a,b)不合法,所以我们就令gcd(a,0)=agcd(a,0)=a,那么原来方程就变为ax=aax=a,显然x=1,y=0x=1,y=0

    辗转相减的用途

    既然有更快的辗转相除,那么辗转相减有什么用呢?
    我们知道gcd(a,b)=gcd(a,ba)gcd(a,b)=gcd(a,b-a),那么容易推广而知gcd(a1,a2,a3, ,an)=gcd(a1,a2a1,a3a2, ,anan1)gcd(a_1,a_2,a_3,cdots ,a_n)=gcd(a_1,a_2-a_1,a_3-a_2,cdots,a_n-a_{n-1}),那么对于一个序列aa的区间gcdgcd,我们可以通过差分的方式快速维护。
    题目:bzoj 5028 小Z的加油店

    应用

    • 求乘法逆元

    因为我们可以发现,逆元式子ax1( mod m)axequiv 1( m mod m)xx为逆元,当gcd(a,m)=1gcd(a,m)=1,它可以写成ax=1+bmacdot x=1+bcdot m,也就是ax+(b)m=1acdot x+(-b)cdot m=1,因为gcd(a,m)1gcd(a,m)|1,所以我们用扩展欧几里得算法求出这个方程的一组解,其中的xx便是它的逆元。友链-逆元求法

    • 求方程的一组解(基本操作)

    • 辗转相除法神奇用法:求以下式子
      i=1ni×pqsum_{i=1}^{n}leftlfloorfrac{i imes p}{q} ight floor
      具体为转换成三角形求内部整点个数。

    • 题目1

    • 题目2

    推荐这个讲解的友链文章IN


  • 相关阅读:
    ubuntu16.04上安装深度学习环境
    QQ音乐付费音乐下载的demo
    python列表按比例或长度拆分
    docker 使用gpu启动及tf限额
    python apscheduler was missed by
    k8s中使用gpu的部署方案
    从字符串中找出最大的数字串,字符串中可以带小数点。--python实现
    linux中批量删除带空格的文件
    tornado中使用python3原生事件循环asyncio
    mysql DATE_FORMAT FROM_UNIXTIME 的区别
  • 原文地址:https://www.cnblogs.com/VictoryCzt/p/10053430.html
Copyright © 2011-2022 走看看