扩展欧几里得算法

裴蜀定理

对于任意正整数 a,b,记 g=(a,b),一定存在整数 x,y,使得 ax+by=g,且能凑出的数一定是 g 的倍数。(扩欧算法能直接解决的问题)

首先由于 a,b 都是 g 的倍数,所以能凑出的数必定是 g 的倍数。

关键在于怎么证明一定存在整数 x,y,使得 ax+by=g

下面我们就抛出这个算法。

扩展欧几里得算法

首先引入欧几里得算法。

g=gcd(b,amodb)(不知道就回普及组来学的实在太强了)

b=0,则 g=a

直接在欧几里得算法里添加内容。

我们从边界情况开始考虑。

b=0 时,要求 ax+by=ax=gcd(a,0)=a,显然 x=1,y=0 是一组解。

我们在递归的时候将 x,y 翻转,于是就求得 by+(amodb)x=gcd(b,amodb)=g

根据余数的定义 amodb=abab

代入可得 by+(abab)x=g

我们将 a,b 系数整理到一块儿。

ax+b(yabx)=g

发现这就是我们需要的形式,于是令 y=yabx

那怎么求多组解呢?

发现 a(xbd)+b(y+ad)=ax+by

那么我们据此可以推出所有的解。

x0,y0 表示我们求得的解。

则所有解 x=x0kbd,y=y+kad

据此发现有无数个解。
关于 x 的最小非负整数解:一个负数加至少多少个正数能变成非负整数,等价于数学意义上的取模;在 C++ 中,可以先取模,再加,再取模。

扩欧直接应用

#include<cstdio>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while

const int N=1;
int n;
int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    #endif
    scanf("%d",&n);
    W(n){
        int a,b,x,y;
        scanf("%d%d",&a,&b);
        exgcd(a,b,x,y);
        printf("%d %d\n",x,y);
    }
    return 0;
}

应用:求解 axb(modm)(当 b=1 时,xa 的逆元)

题目传送门

考虑变形可得 ax=my+bmodm,也可以变为 ax=my+b(就是将部分的 mb)。

axmy=b

y=yax+my=b

先用扩欧解 b=(a,m) 的情况,然后先判断是不是倍数,然后扩大 b(a,m)

#include<cstdio>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while

const int N=1;
int n;
int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    #endif
    scanf("%d",&n);
    W(n){
        // printf("n=%d\n",n);
        int a,b,m,x,y;
        scanf("%d%d%d",&a,&b,&m);
        int d=exgcd(a,m,x,y);
        if(b%d)puts("impossible");
        else printf("%lld\n",1ll*b*x/d%m);
    }
    return 0;
}

本文作者:wscqwq

本文链接:https://www.cnblogs.com/wscqwq/p/17644365.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   wscqwq  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起