【数学】欧几里得算法
验证链接:洛谷P5656 | 洛谷P1082 | 洛谷P3811
LCE1这个算法找到的是x的最小非负整数解。剩下的事情交给倍增算法。
注意特判0和负数的情况,下面存在除以0的时候。假如传入的数字有负数,则返回值需要特殊处理。
namespace exGCD {
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(b == 0) {
x = 1, y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y), t;
t = x, x = y, y = t - a / b * y;
return d;
}
// ax + by = c
int LCE1(ll a, ll b, ll c, ll &x, ll &y, ll &dx, ll &dy) {
ll d = exgcd(a, b, x, y), t = b / d;
if(c % d != 0) {
// no solution
x = -1, y = -1, dx = -1, dy = -1;
return -1;
}
// solution is: x = x + k * dx, y = y - k * dy
x = ((x % t) * (c / d % t) % t + t) % t;
y = (c - a * x) / b, dx = t, dy = a / d;
return 0;
}
// ax = r mod m
int LCE2(ll a, ll r, ll m, ll &x, ll &dx) {
ll y, d = exgcd(a, m, x, y), t = m / d;
if(r % d != 0) {
// no solution
x = -1, dx = -1;
return -1;
}
// solution is: x = x + k * dx
x = ((x % t) * (r / d % t) % t + t) % t, dx = t;
return 0;
}
ll inv(ll a, ll m) {
ll x, y, d = exgcd(a, m, x, y);
if(d != 1) {
// no solution
return -1;
}
x = (x % m + m) % m;
// solution is: x = x + m / d
return x;
}
}