• [数学]gcd&exgcd


    gcd & exgcd


    gcd

    我们规定:

    [egin{equation}gcd(a,b)=a,b的最小公倍数 onumberend{equation} ]

    显然我们有:

    [egin{align}a&=k_1 imes gcd(a,b) onumber\b&=k_2 imes gcd(a,b) onumber\a\%b&=a-lfloorfrac{a}{b} floor imes b onumber\&=k_1 imes gcd(a,b)-lfloorfrac{a}{b} floor imes k_2 imes gcd(a,b) onumber\&=gcd(a,b) imes (k_1-k_2 imeslfloorfrac{a}{b} floor) onumberend{align} ]

    显然(k_1,k_2,lfloorfrac{a}{b} floor)均为整数,且(gcd(k_1,k_2 imes lfloorfrac{a}{b} floor)=1)

    (a\%b)也是(gcd(a,b))的倍数

    那么我们就有:

    [egin{equation} gcd(a,b)=gcd(b,a\%b)quad当且仅当a\%b=0时,gcd(a,b)=a onumberend{equation} ]

    下面是代码实现:

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

    exgcd

    我们要求解形如下面的方程的一组整数解:

    [egin{align}ax+by=d onumberend{align} ]

    首先,这样的方程并不是一定有解的,我们有裴蜀定理:

    [当且仅当gcd(a,b)|d时,ax+by=d有整数解 ]

    所以如果方程有解,我们就可以操作一下它:

    [egin{align}ax+by&=k imes gcd(a,b) onumber\a(x_1 imes k)+b(y_1 imes k)&=k imes gcd(a,b) onumber\ax_1+by_1&=gcd(a,b) onumberend{align} ]

    于是我们就把方程简化到上面的形式,它的一组解是((x_1,y_1))

    那么原方程的一组解就是((x_1 imes k,y_1 imes k)),其中(k=frac{d}{gcd(a,b)})

    接下来我们考虑怎么解简化后的方程:

    [egin{align}ax+by&=gcd(a,b) onumber\ax+by&=gcd(b,a\%b) onumber\bx'+(a\%b)y' &=gcd(b,a\%b) onumber\bx'+(a-lfloorfrac{a}{b} floor imes b)y'&=ax+by onumber\bx'+ay'-b imeslfloorfrac{a}{b} floor imes y'&=ax+by onumber\ay'+b(x'-lfloorfrac{a}{b} floor imes y')&=ax+by onumber\ay'+b(x'-lfloorfrac{a}{b} floor imes y')&=gcd(b,a\%b) onumberend{align} ]

    我们可以根据最后一行式子递归下去求解

    直到(a\%b=0)时,(gcd(a,b)=0),此时的一组解为(left{egin{align}x=1 onumber\y=0 onumberend{align} ight.)

    这是最后一层的答案,我们考虑怎么通过这个得到上一层的答案

    观察倒数第二行的式子,我们可以得到(left{egin{align}x&=y' onumber\y&=x'-lfloorfrac{a}{b} floor imes y' onumberend{align} ight.)

    通过这个我们就可以一层一层向回推,得到最后的解了

    代码:

    #include<bitsstdc++.h>
    
    using namespace std;
    
    int gcd(int a,int b){
        return b?a:gcd(b,a%b);
    }
    
    void exgcd(int a,int b,int &d,int &x,int &y){
        if(b==0){
            d=a;
            x=1;
            y=0;
        }else{
            exgcd(b,a%b,d,y,x);
            y=y-a*x;
        }
    }
    
    int main(){
        int a,b,d;
        scanf("%d%d%d",&a,&b,&d);
        int tmp=gcd(a,b);
        if(d%tmp)
            printf("no solution!
    ");
        else{
            int x,y;
            exgcd(a,b,tmp,x,y);
            x=x*d/tmp;
            y=y*d/tmp;
            printf("%d %d
    ",x,y);
        }
    }
    
  • 相关阅读:
    协议(五)-从电报机到智能手机
    协议(四)-通信发展史
    NDK历史版本
    android onKeyDown
    设计模式
    Android获取系统时间的多种方法
    USB 3.0规范中译本 第5章 机械结构
    ES6新特性
    08_SQLyog图形化工具介绍
    07_聚合函数,分组查询&limit关键字
  • 原文地址:https://www.cnblogs.com/2016gdgzoi316/p/13632177.html
Copyright © 2020-2023  润新知