-拓展欧几里得,以及乘法逆元
参考的大佬博客:详解扩展欧几里得算法(扩展GCD) - Seaway-Fu - 博客园 (cnblogs.com)
(32条消息) 扩展欧几里得算法_zthgreat的博客-CSDN博客_扩展欧几里得算法
基本都是别人的内容,主要用于自用
欧几里得
欧几里得算法基于gcd(a,b)=gcd(b%a,a)(相当于a,b相互减去对方的个数,a%b=a−b⌊a/b⌋a%b=a−b⌊a/b⌋)用于求解两数最大公约数
在这里我们先引入裴蜀定理
裴蜀定理
对于任意的整数a,b,都存在一对整数x,y,使得ax+by=gcd(a,b)ax+by=gcd(a,b)成立
假设存在一对整数x,y,使得其一定会满足b×x+(a%b)×y=gcd(b,a%b)b×x+(a%b)×y=gcd(b,a%b), 因为a%b=a−b⌊a/b⌋a%b=a−b⌊a/b⌋,所以有以下的推导:
b×x+(a%b)×y=gcd(b,a%b)=bx+(a−b⌊a/b⌋)y=ay−b(x−⌊a/b⌋y)
可得结论:ax′+by′=gcd(a,b)
那么可以推出:如果一个数mm满足:ax+by=mm,那么这个mm一定是gcd(a,b)的倍数。
那么对于一个经典方程ax+by=1ax+by=1,利用裴蜀定理,我们有:gcd(a,b)=1,即a,b一定互质。
递归版本
#include<stdio.h> int main() { int a,b,s,t,gcd; int exgcd(int a,int b,int *x,int *y); while(scanf("%d%d",&a,&b)!=EOF) { gcd=exgcd(a,b,&s,&t); printf("%d %d\n",s,t); } return 0; } int exgcd(int a,int b,int *x,int *y)//扩展欧几里得算法; { if(b==0) { *x=1; *y=0; return a; } int ret=exgcd(b,a%b,x,y); int t=*x; *x=*y; *y=t-a/b*(*y); return ret; }
非递归版本
int exgcd(int a,int b,int &x,int &y) { int xi_1,yi_1,xi_2,yi_2; xi_2=1,yi_2=0; xi_1=0,yi_1=1; x=0,y=1; int r=a%b; int q=a/b; while (r) { x=xi_2-q*xi_1; y=yi_2-q*yi_1; xi_2=xi_1; yi_2=yi_1; xi_1=x,yi_1=y; a=b; b=r; r=a%b; q=a/b; } return b; }
用途1:解不定方程ax+by=gcd(a,b)
由于是是不定式,x和y只需要得到返回值即可
用途二:解乘法逆元
当我们用扩展欧几里得算法找到一组 x 和 y 满足 时,就可以得出 ,也就是说 x 是 a 的乘法逆元。
显然,如果 x 是 a 的乘法逆元,那么所有的 也是 a 的乘法逆元。这表明,一定有 a 的一个乘法逆元在区间 内。
这是找到 n 在模 p 下的乘法逆元的一个算法,使用了上面的 exgcd:
int inv(int n, int p) { int x, y; if(exgcd(n, p, x, y) == 1) { x = x % p; return x >= 0 ? x : p + x; } else { return -1; } }
如果返回 -1,表示乘法逆元不存在。