扩展欧几里得算法exgcd基本运用 与 exgcd求逆元
作者:互联网
基础用法
给定 $ n $ 对正整数 $ a_i, b_i $,对于每对数,求出一组 $ x_i, y_i $,使其满足 $ a_i \times x_i + b_i \times y_i = gcd(a_i, b_i) $。
裴蜀定理
对于任意正整数\(a, b\),那么一定存在非零整数\(x,y\)使得\(ax + by = gcd(a , b )\)
假设\(ax + by = d\),那么\(d\)一定要是\(gcd(a,b)\)的倍数
显然,\(a,b,ax,by,ax+by\)都是\(gcd(a,b)\)的倍数,因此\(d = ax+by\)是\(gcd(a,b)\)的倍数
因此\(d\)最小是一倍的\(gcd(a,b)\),也就是\(d=gcd(a,b)\)
所以这个方程\(ax + by = d\)最小的解便是\(gcd(a,b)\)
因此题中的方程一定有解
这个解就由扩展欧几里得算法
解出
想法
先回顾欧几里得算法
:
if(!b)
{
return a;
}
return gcd(b, a % b);
\(1.\) 先看if(!b)
的情况,当\(b=0\)时,\(gcd(a,b)=gcd(a,0)=a\)
代入原式中,\(a\times x + 0 \times y= a\)
解得\(x = 1, y = 0\)
\(2.\) if(b)
时,用int d
记录exgcd(b, a % b, y, x)
由于此处颠倒了\(a,b\)的顺序,因此传入\(x,y\)时也要颠倒
\[原式 = by + (a\%b)x = d \]此处\(a\%b = a - \lfloor \frac{a}{b}\rfloor \times b\)
由于$a\div b = \lfloor \frac{a}{b}\rfloor \dots a%b $
所以\(a\%b = a - \lfloor \frac{a}{b}\rfloor \times b\)
因此
\[by+(a - \lfloor \frac{a}{b}\rfloor \times b)x =d \]把\(x\)乘进去,得:
\[ax + b(y- \lfloor \frac ab\rfloor x) =d \]
码来!
#include <iostream>
using namespace std;
int Extended_Euclidean(int a, int b, int &x, int &y) // 记得加引用
{
if(!b)
{
x = 1;
y = 0;
return a;
}
int d = Extended_Euclidean(b, a % b, y, x); // 颠倒
y = y - a / b * x; // 套公式
return d; // 返回gcd(a, b)
}
int main()
{
int n;
int a, b, x, y;
scanf("%d", &n);
while (n -- )
{
scanf("%d%d", &a, &b);
Extended_Euclidean(a, b, x, y); // 算法写全名会不会霸气一点 []~( ̄▽ ̄)~*
printf("%d %d\n", x, y);
}
return 0;
}
扩展欧几里得算法求逆元
我们已知当\(p\)是质数的时候,可以用快速幂算法
求逆元
详见这篇博客
那么,当\(p\)不是质数的时候,用什么呢?
答案是:扩展欧几里得算法
\(a\)有逆元的充分必要条件是\(a\)与\(p\)互质,因此\(gcd(a, p) = 1\)
所以设逆元为\(x\),则\(a * x \equiv 1 \bmod p\)
则\(ax + py = 1\)
那么exgcd(a, p, x, y)
就能算出来
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
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 = y - a / b * x; // 套公式
return d; // 返回gcd(a, b)
}
int main()
{
int n;
cin >> n;
while(n--)
{
int x, y, a, p;
cin >> a >> p;
int d = exgcd(a, p, x, y);
if(d == 1) // 有解
{
cout << ((LL)x + p) % p << endl; // 保证正数
}
else puts("impossible");
}
return 0;
}
感谢观看~
标签:return,gcd,int,欧几里得,exgcd,times,逆元,ax 来源: https://www.cnblogs.com/MoyouSayuki/p/16513704.html