基础用法
给定 $ 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;
}
感谢观看~
原创文章,作者:306829225,如若转载,请注明出处:https://blog.ytso.com/276579.html