zoukankan      html  css  js  c++  java
  • [数论]Gcd/ExGcd欧几里得学习笔记

    (Q):什么是(GCD)?

    • (GCD)

    (GCD),即最大公约数((Greatest Common Divisor)

    对于两个自然数(a,b),定义(GCD(a,b))(a,b)所有公共约数中最大的一个,即(GCD(a,b)=max{xin N^*,x|a)(x|b})

    然后是关于(GCD)的算法即其扩展


    (Part1) 欧几里得算法

    (Q):这个算法有什么用?

    此算法可以在(log)级别里求出两个数(a,b)(GCD)

    • 欧几里得算法

    对于(a,b),设它们的(GCD)(d)

    则有:(d|a)(d|b)

    (a=k*{}b+r(k=leftlfloorfrac{a}{b} ight floor,r=amod b))

    则:(d|(a-k*{}b)),即(d|r)

    所以(GCD(a,b)=GCD(b,r)=GCD(b,amod b))

    最后递归求解,可在(O(log_2a))内得解。

    时间复杂度 (O(log_2a))

    空间复杂度 (O(log_2a))(递归栈)

    实际复杂度一般到不了此上界。

    代码:

    //求GCD(a,b)
    #include <cstdio>
    
    int GCD(int a,int b)
    {
        return b?GCD(b,a%b):a;
        //当b为0时,GCD(a,0)=a,充当递归边界。
    }
    
    int main()
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d
    ",GCD(a,b));
        return 0;
    }
    

    (Part2) 扩展欧几里得

    (Q):这个奇怪的算法又是什么啊?

    首先,先来看一个不定方程:

    [ax+by=c ]

    扩展欧几里得就是用来求此方程的不定解((x,y))的。

    准备知识:

    • (Bezout)定理

    对于两个整数(a,b)存在一对整数(x,y),满足(ax+by=GCD(a,b))

    证明:

    在调用欧几里得算法时,当(b=0),显然有(x=1,y=0)满足定理。

    (b ot= 0)时,若已经求得,(x,y),使得

    [bx+(amod b)y=GCD(b,amod b) ]

    [bx+(a-bleftlfloorfrac{a}{b} ight floor)y=GCD(b,amod b) ]

    [ay+b(x-leftlfloorfrac{a}{b} ight floor y)=GCD(b,amod b) ]

    (x'=y,y'=x-leftlfloorfrac{a}{b} ight floor y),则有

    [ax'+by'=GCD(b,amod b)=GCD(a,b) ]

    利用数学归纳法,知道(Bezout)成立。

    同时,我们可以利用此定理求出一组(ax+by=GCD(a,b))的解。

    时间复杂度 (O(log_2a))

    空间复杂度 (O(log_2a))

    代码:

    //求x,y使得ax+by=GCD(a,b),同时得到GCD(a,b)
    #include <cstdio>
    
    int ExGCD(int a,int b,int &x,int &y)
    {
        if(!b){x=1,y=0;return a;}//递归边界
        int GCD=ExGCD(b,a%b,x,y);
        int Tmp=x;
        x=y,y=Tmp-a/b*y;
        return GCD;
    }
    
    int main()
    {
        int a,b,GCD,x,y;
        scanf("%d%d",&a,&b);
        GCD=ExGCD(a,b,x,y);
        printf("%d %d %d
    ",GCD,x,y);
        return 0;
    }
    

    接着回到正题:对于方程(ax+by=c),它有解仅当(GCD(a,b)|c)

    证明?不会,记住就行,毕竟显然。

    接着,求出方程(ax+by=GCD(a,b))的一组解,则:

    [ax+by=GCD(a,b) ]

    [frac{c}{GCD(a,b)}*{}(ax+by)=c ]

    [a*frac{cx}{GCD(a,b)}+b*frac{cy}{GCD(a,b)}=c ]

    于是就有了一组解:(x'=frac{cx}{GCD(a,b)},y'=frac{cy}{GCD(a,b)})(对(x,y)同时乘上(frac{c}{GCD(a,b)}))

    于是问题得解。

    时间复杂度 (O(log_2a))

    空间复杂度 (O(log_2a))

    代码:

    //求x,y使得ax+by=c,同时得到GCD(a,b)
    #include <cstdio>
    
    int ExGCD(int a,int b,int &x,int &y)
    {
        if(!b){x=1,y=0;return a;}//递归边界
        int GCD=ExGCD(b,a%b,x,y);
        int Tmp=x;
        x=y;
        y=Tmp-a/b*y;
        return GCD;
    }
    
    int main()
    {
        int a,b,c,GCD,x,y;
        scanf("%d%d%d",&a,&b,&c);
        GCD=ExGCD(a,b,x,y);
        if(c%GCD)return puts("Orz I cannot find it!"),0;//无解
        int d=c/GCD;
        printf("%d %d %d
    ",GCD,x*d,y*d);
        return 0;
    }
    

    关于通解以及(x)最小正整数解。

    (d=GCD(a,b))

    (x_0,y_0)(ax+by=GCD(a,b))的一组特解,

    (x=x_0+km,y=y_0+kn(kin mathbb{Z}))为方程的通解表示(k为任意整数),

    则:

    [ax+by=ax_0+by_0 ]

    [a(x_0+km)+b(y_0+kn)=ax_0+by_0 ]

    [am+bn=0 ]

    显然,当(m=-b,n=a)时等式成立。

    又因为要把(m,n)比例降到最小,所以同时除去(GCD)

    最后的通解表示为:

    [x=x_0-kfrac{b}{d},y=y_0+kfrac{a}{d}(kin mathbb{Z}) ]

    同理,对于方程(ax+by=c)的通解为:

    [x=frac{c}{d}x_0-kfrac{b}{d},y=frac{c}{d}y_0+kfrac{a}{d}(kin mathbb{Z}) ]

    所以求(x)的最小整数解只需要将(xmod frac{b}{d})再推出(y)即可。

    时间复杂度 (O(log_2a))

    空间复杂度 (O(log_2a))

    代码:

    //求ax+by=c的x最小正整数解。
    #include <cstdio>
    
    int ExGCD(int a,int b,int &x,int &y)
    {
        if(!b){x=1,y=0;return a;}//递归边界
        int GCD=ExGCD(b,a%b,x,y);
        int Tmp=x;
        x=y;
        y=Tmp-a/b*y;
        return GCD;
    }
    
    int main()
    {
        int a,b,c,d,x,y;
        scanf("%d%d%d",&a,&b,&c);
        d=ExGCD(a,b,x,y);
        if(c%d)return puts("Orz I cannot find it!"),0;//无解
        x*=c/d,y*=c/d;
        int f=b/d;
        x=(x%f+f)%f;
        y=(c-a*x)/b;
        printf("%d %d
    ",x,y);//x最小正整数解。
        return 0;
    }
    

    所有性质证明到此结束。


    欧几里得是个好东西,然而我不会用

    数论博大精深,不能就此止步,还要继续探索。

    祝自己(++OI::RP)

  • 相关阅读:
    C# winform窗体自动停靠控件
    C# winform treeview checkbox 选中 循环 遍历
    解决WinForm(C#)中MDI子窗体最大化的问题
    tabcontrol的alignment属性设置成Left或Right时,tabPage的text内
    用伪随机数生成器Random生成随机数序列
    C#限制MDI子窗体重复打开——C#判断窗体是否已经打开 多种方法 20120626更新
    管理软件中融入“人、时间、流程”维度,提升软件社会价值
    如何让管理软件提升企业战略执行力
    2007年11月17日上午 ITIL与ITSM QQ群聊天记录: 欢迎加入QQ群:48132184
    Sharepoint 站点下应用程序虚拟路径下出现"不能进行输出缓存处理",错误ID 5787 解决方法
  • 原文地址:https://www.cnblogs.com/LanrTabe/p/10370627.html
Copyright © 2011-2022 走看看