欧几里得算法
也叫辗转相除法,用于求两个数的最大公约数
int gcd(int a,int b)
{
return b ? gcd(b, a % b) : a;
}
b为 0 时,最大公约数就是a,0可以整除任何数
不为 0 时,最大公约数就是gcd(b, a % b)
扩展欧几里得算法
AcWing 877. 扩展欧几里得算法
扩展欧几里得算法用于求解方程 ax + by = gcd(a,b) 的解 x 和 y
① 当 b = 0 时,ax + by = a,所以 x = 1,y = 0 就是一组解
② 当 b ≠ 0 时,
已知 ,gcd(a,b) = gcd(b,a % b)
设 gcd(b,a % b) 构成的方程解为x1、y1 ,则:
bx1 + (a % b)y1 = gcd(b,a % b)
bx1 + (a - ⌊a / b⌋ * b)y1 = gcd(b,a % b)
ay1 + b(x1 - ⌊a / b⌋ * y1) = gcd(b,a % b) = gcd(a,b) = ax + by
所以,x = y1 ,y = x1 - ⌊a / b⌋ * y1
#include<iostream>
using namespace std;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x = 1, y = 0;
return a;
}
else
{
int x1, y1, gcd;
gcd = exgcd(b,a%b,x1,y1);
x = y1, y = x1 - a / b * y1;
return gcd;
}
}
int main()
{
int n;
cin >> n;
while(n--)
{
int a, b, x, y;
cin >> a >> b;
exgcd(a,b,x,y);
cout << x <<" "<<y<<endl;
}
}
K * M % N = 1可以转化为 K * M + Q * N = 1,我们可以用扩展欧几里得算法求解K,为什么不用快速幂求逆元呢,因为快速幂是由费马定理推导的,而费马定理的前提是 N 为质数,此题 N 并不是质数,所以只能用扩展欧几里得啦!
#include<iostream>
using namespace std;
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()
{
int a,b,x,y;
cin >> a >> b;
exgcd(a,b,x,y);
cout << (x % b + b) % b;
}
扩展欧几里得算法求线性同余方程
AcWing 878. 线性同余方程
已知 ax ≡ b(mod m)
存在 y ∈ Z,使得 ax = my + b
即,ax - my = b,也就是 ax + my = b
由扩展欧几里得算法可以求出 ax + my = gcd(a,b) 的解,那么怎么 ax + my = b 的解呢,很简单
ax + my = gcd(a,b) 等式两边同乘 b / gcd(a,b) 即可
最后注意, 要使 ax + my = b 有解,b 必须是 gcd(a,b) 的倍数(因为 a 是gcd的倍数,b 也是gcd的倍数,所以 ax + by 也一定是gcd的倍数)
#include<iostream>
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;
}
else
{
int x1, y1, gcd;
gcd = exgcd(b,a % b,x1,y1);
x = y1, y = x1 - a/b * y1;
return gcd;
}
}
int main()
{
int n;
cin >> n;
while(n--)
{
int a, b, m, x, y;
cin >> a >> b >> m;
int gcd = exgcd(a,m,x,y);
if(b % gcd == 0) cout << (LL)x * b / gcd % m << endl;
else cout <<"impossible"<< endl;
}
}