zoukankan      html  css  js  c++  java
  • 欧几里得及扩展欧几里得算法

      欧几里得算法 这个就是常说的辗转相除法,用于计算两个整数 $a,b$ 的最大公约数,即$$gcd(a,b)=gcd(b,a;mod;b)$$

    int gcd(int a,int b){
        return b==0 ? a : gcd(b,a%b);
    }
    View Code

      展欧几里德算法 是用来在已知 $a,b$ 求一组整数解 $x,y$ 使它们满足等式$$ax+by=gcd(a, b)$$

      推导如下:

      设 $a>b$

       显然当 $b=0$ , $gcd(a,b)=a$ 时,$x=1$ , $y=0$ ;

      当 $a>b>0$ 时,设$$ax_1+by_1= gcd(a,b)$$$$bx_2+(a;mod;b)y_2=gcd(b,a;mod;b)$$

      根据朴素的欧几里得算法,可得$$ax_1+by_1=bx_2+(a;mod;b)y_2$$$$ax_1+by_1=bx_2+(a- lfloor frac{a}{b} floor b)y_2$$$$ax_1+by_1=ay_2+b(x_2- lfloor frac{a}{b}  floor y_2)$$

      根据恒等定理得$$x_1=y_2$$$$y_1=x_2- lfloor frac{a}{b} floor y_2$$

      这样我们就得到了求解 $x_1,y_1$ 的方法:$x_1,y_1$ 的值基于 $x_2,y_2$

      上面的思想是以递归定义的,因为 $gcd$ 不断的递归求解一定会有个时候 $b=0$ ,所以递归可以结束

    int exgcd(int a,int b,int &x1,int &y1){
        if(!b){
            x1=1;
            y1=0;
            return a;
        }
        ans=exgcd(b,a%b,x1,y1);
        int t=x1;
        x1=y1;
        y1=t-a/b*y1;
        return ans;
    }
    View Code

       下面是一些重要的结论

      结论一 设 $a,b,c$ 为任意整数,若方程 $ax+by=c$ 的一组整数解为 $(x_0,y_0)$ ,则他们的任意整数解都可以写成 $(x_0+kb',y_0-ka')$ ,其中 $a'=frac{a}{gcd(a,b)}$ , $b'=frac{b}{gcd(a,b)}$ , $k in Z$

      结论二 设 $a,b,c$ 为任意整数,$g=gcd(a,b)$ ,方程 $ax+by=g$ 的一组整数解为 $(x_0,y_0)$ ,则当 $c$ 是 $g$ 的倍数时,$ax+by=c$ 的一组整数解是 $(x_0 frac{c}{g},y_0 frac{c}{g})$ ;当 $c$ 不是 $g$ 的倍数时,无整数解

      然后洛谷上有道关于扩展欧几里得很经典的题 青蛙的约会 下面是AC代码

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define ll long long
    
    ll x,y,m,n,l;
    ll ans,x1,y1;
    
    ll exgcd(ll a,ll b,ll &x1,ll &y1){
        if(!b){
            x1=1;
            y1=0;
            return a;
        }
        ans=exgcd(b,a%b,x1,y1);
        ll t=x1;
        x1=y1;
        y1=t-a/b*y1;
        return ans;
    }
    
    int main(){
        scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&l);
        ll a=n-m,c=x-y;
        if(a<0){
            a=-a;
            c=-c;
        }
        exgcd(a,l,x1,y1);
        if(c%ans) printf("Impossible");
        else printf("%lld",((x1*(c/ans))%(l/ans)+(l/ans))%(l/ans));
        //处理负数的神奇方法 
        
        return 0;
    }
    View Code
  • 相关阅读:
    js-----面向对象=====>工厂模式/构造函数/原型模式
    MarkDown语法
    Vue 基础篇
    CSS 预处理语言之 less 篇
    Git常用命令
    与 JSON 相关的一些操作 (项目中用到一部分,后续逐渐完善)
    [转] -- html5手机网站自适应需要加的meta标签
    [转] -- 最全前端资源汇集
    json和jsonp的区别,ajax和jsonp的区别
    对象
  • 原文地址:https://www.cnblogs.com/Pedesis/p/10339787.html
Copyright © 2011-2022 走看看