扩展GCD

引入

  扩展欧几里得算法,简称 exgcd,一般用来求解不定方程,求解线性同余方程,求解模的逆元等

  引理:存在 x , y 使得 gcd(a,b)=ax+by

  证明:

         当 b=0 时,gcd(a,b)=a,此时 x=1 , y=0

         当 b!=0 时,

         设 ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2

         又因 a%b=a-a/b*b

         则   ax1+by1=bx2+(a-a/b*b)y2

      ax1+by1=bx2+ay2-a/b*by2

      ax1+by1=ay2+bx2-b*a/b*y2

      ax1+by1=ay2+b(x2-a/b*y2)

    解得 x1=y2 , y1=x2-a/b*y2

    因为当 b=0 时存在 x , y 为最后一组解

    而每一组的解可根据后一组得到

    所以第一组的解 x , y 必然存在

CODE:

void exgcd(int a, int b, int &x, int &y) {
    if(b == 0) x = 1, y = 0;
    else exgcd(b, a % b, y, x), y -= a / b * x;
}

  exgcd 解不定方程(使用不将a与b转为互质的方法)

 

  对于 ax+by=c 的不定方程,设 r=gcd(a,b)

 

  当 c%r!=0 时无整数解

 

  当 c%r=0 时,将方程右边 *r/c 后转换为 ax+by=r 的形式

 

  可以根据扩展欧几里得算法求得一组整数解 x0 , y0

 

  而这只是转换后的方程的解,原方程的一组解应再 *c/r 转变回去

 

  (如 2x+4y=4 转换为 2x+4y=2 后应再将解得的 x , y 乘上2)

 

  则原方程解为 x1=x0*c/r , y1=x0*c/r

 

  通解 x=x1+b/r*t , y=y1-a/r*t ,其中 t 为整数

 

  证明:

 

    将 x , y 带入方程得

 

    ax+ab/r*t+by-ab/r*t=c

 

    ax+by=c

 

    此等式恒成立

 

    得证

 

  这里 b/r 与 a/r 为最小的系数,所以求得的解是最多最全面的

 

栗1(题目戳这里

  这道题求得就是最小解,所以只要输出(x % b + b) % b就可以啦

  CODE:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

void exgcd(int a, int b, int &x, int &y) {
    
    if(b == 0) x = 1, y = 0;
    else exgcd(b, a % b, y, x), y -= a / b * x;
}

int main() {

    int n, m; scanf("%d%d", &n, &m);
    
    int x, y;
    
    exgcd(n, m, x, y);

    printf("%d\n", (x+m)%m);

    return 0;
}

练习

https://www.luogu.org/problemnew/show/P2613
POJ 1061 http://poj.org/problem?id=1061
POJ 2115 http://poj.org/problem?id=2115
POJ 2142 http://poj.org/problem?id=2142
UVA 10090 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1031
http://codevs.cn/problem/1213/

posted @ 2018-08-15 19:43  惜梦园  阅读(152)  评论(0)    收藏  举报