zoukankan      html  css  js  c++  java
  • 扩欧 裴蜀 逆元

    引理

    • 如果任意整数a、b不都为0,则gcd(a,b)是集合A={ax+by:x,y∈Z}的最小正元素。

    证明:

    • 设s是A中的最小正元素,也就是s=ax′+by′。
    • 设q=⌊a / s⌋,则

    a%s=a−qs=a−q(ax+by)=a(1−qx)+b(−qy)

    • 因此,a%s∈A。由于0≤a % s<s,所以a%s=0。同理,b%s=0。因此,s | gcd(a,b),即gcd(a,b)>=s
      同时,因为s∈A,所以gcd(a,b)|s,也就是说gcd(a,b)≤s。得到gcd(a, b)=s。

    扩展欧几里得算法.

    扩展欧几里得算法(扩O)能在求gcd(a,b)的同时求出丢番图方程ax+by=gcd(a,b)的解。

    然而怎么求呢?我们观察gcd(a,b)=gcd(b,a%b),所以设如下两个方程:

    ax+by=gcd(a,b)=d
    bx′+(a%b)y′=gcd(b,a%b)
    明显gcd(a,b)=gcd(b,a%b),也就是ax+by=bx′+(a%b)y′。

    为了求得x与y,我们需要保证a,b不变,所以:ax+by=bx′+(a%b)y′=bx′+(a−[a/b]∗b)y′
    =ay′+b(x′–[a/b]y′) ([a/b]表示a/b的值向下取整。)

    所以可得恒等关系:x = y’ , y = (x’ – [a/b]y’)。一层层往上推,这样就求出了一组特解。

    那么如何求全解呢?直接给出递推式:

    x=x0+(b/gcd)∗t
    y=y0–(a/gcd)∗t
    明显,b/gcd与a/gcd是互素的,也就是说它们的gcd为1。如果它们再除以一个值,某些解可能就不是整数了。

    裴蜀定理

    扩O有什么卵用吗?其实它可以求线性丢番图方程(不定方程)。

    对任何整数a、b和它们的最大公约数d,关于未知数x和y的线性丢番图方程(称为裴蜀等式):

    ax+by=m
    有解当且仅当m是d的倍数。这是由于任何一个a和b的线性组合都被gcd(a, b)整除。

    裴蜀等式有解时必然有无穷多个整数解,每组解x、y都称为裴蜀数,可用扩O求得。只要将x与y同时乘上 m / gcd(a,b)就行了。

    特别来说,方程 ax+by=1有解当且仅当整数a和b互素。(因为 gcd(a,b)=1)

    乘法逆元

    给定一个形如 ax ≡ 1(%m)的关于x的方程,x即为a关于m的乘法逆元。

    怎么求呢?我们把它等价一下:ax%m=1%m=1,ax=m(−y)+1,ax+my=1。
    也就是说,只要求出ax+my=1这个方程的解就行了。是不是有点熟悉?对,用扩O+裴蜀求出x,y。

    (注意要满足 gcd(a,m)=1)

    但是明显,一道题目出给你不可能让你输出无数解,通解也不现实,一般是让你求出x最小的正整数解。那怎么办呢?

    x的通解是x0+m/gcd∗t,在乘法逆元情况下gcd=1,所以不用考虑。所以x的通解是x0+mt。

    因为通解是x0+mt,明显最小正整数解的区间是,)[0,m),所以似乎只要让x0 % m就可以找到最小解了。

    可是万一x0 % m是负数呢?答案x=(x0%b+b)%b。

    因为如果x0为负,答案就是b减去x0 % b的绝对值。如果x为正,还要除以b。

    说了这么多,理一下思路:扩O能求出ax+by=gcd(a,b)。那么只要整数m=整数∗gcd(a,b),方程就有解,这种方程叫做不定方程。同时根据乘法逆元的性质,只当gcd(a,b)=1时a,b互为乘法逆元。


    下面贴代码:

    Luogu P1082 同余方程

    求关于 x 的同余方程 ax ≡ 1 (% b)的最小正整数解。

    #include <cstdio>
    using namespace std;
    int a, b;
    void exgcd(int a, int b, int &x, int &y){
        if (b){
            exgcd(b, a%b, x, y); int tmp=x;
            x=y; y=tmp-(a/b)*y;
        } else x=1, y=0;
        return;
    }
    int main(){
        scanf("%d%d", &a, &b);
        int x, y;
        exgcd(a, b, x, y);
        x=(x%b+b)%b;
        printf("%d", x);
        return 0;
    }
    
  • 相关阅读:
    完成了一次子网站向顶级网站的迁移
    Sharepoint中子网站迁移到顶级网站的方法
    Chain Of Responsibility——设计模式学习笔记
    短信PDU编码解析
    Decorator模式——设计模式学习笔记
    adb常用命令和logcat使用
    Explicit——谨慎定义隐式类型转换函数
    FlyWeight模式——设计模式学习笔记
    Facade模式——设计模式学习笔记
    宏——#define与#undef
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/9257239.html
Copyright © 2011-2022 走看看