From be147b16eeacdde5664590e10915a3eec135b03e Mon Sep 17 00:00:00 2001 From: Ariel Date: Mon, 19 Feb 2024 14:05:23 +0800 Subject: [PATCH] Create exgcd.cc --- number/exgcd.cc | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 number/exgcd.cc diff --git a/number/exgcd.cc b/number/exgcd.cc new file mode 100644 index 0000000..7a02a14 --- /dev/null +++ b/number/exgcd.cc @@ -0,0 +1,60 @@ +namespace Exgcd { + struct exgcd_solution_t { + ll x, y, gcd; + }; + + struct diophantine_solution_t { + exgcd_solution_t x_min, y_min; + ll range; + }; + + // solve `ax + by = gcd(a, b)` + optional exgcd(ll a, ll b) { + if (a < 0 || b < 0 || a == 0 && b == 0) return nullopt; + ll x, y, g; + function __exgcd = [&__exgcd, &x, &y, &g] (ll a, ll b) -> void { + if (b == 0) { + g = a, x = 1, y = 0; + } else { + __exgcd(b, a % b); + swap(x, y); + y -= a / b * x; + } + }; + __exgcd(a, b); + return {{ x, y, g }}; + }; + + optional inverse(ll a, ll b) { + auto raw = exgcd(a, b); + if (raw == nullopt || raw.value().gcd != 1) { + return nullopt; + } else { + return mod(raw.value().x, b); + } + } + + // find minimal non-negative integral solutions of `ax + by = c` + optional diophantine(ll a, ll b, ll c, bool force_positive = false) { + if (a < 0 || b < 0 || a == 0 && b == 0) return nullopt; + auto raw = exgcd(a, b).value(); + if (c % raw.gcd) { + return nullopt; + } else { + ll x = raw.x * c / raw.gcd, y = raw.y * c / raw.gcd; + ll kx = force_positive ? (x <= 0 ? (-x) * raw.gcd / b + 1 : 1 - (x + b / raw.gcd - 1) * raw.gcd / b) : (x <= 0 ? ((-x) + b / raw.gcd - 1) * raw.gcd / b : (- x * raw.gcd / b)); + ll ky = force_positive ? (y <= 0 ? (- 1 - (-y) * raw.gcd / a) : (y + a / raw.gcd - 1) * raw.gcd / a - 1) : (y <= 0 ? (- ((-y) + a / raw.gcd - 1) * raw.gcd / a) : y * raw.gcd / a); + return {{ { x + b * kx / raw.gcd , y - a * kx / raw.gcd , raw.gcd }, { x + b * ky / raw.gcd , y - a * ky / raw.gcd, raw.gcd }, abs(kx - ky) + 1 }}; + } + } + + // find the minimal non-negative integral solution of `ax = b (mod n)` + optional congruential(ll a, ll b, ll n) { + auto sol = diophantine(a, n, b); + if (sol == nullopt) { + return nullopt; + } else { + return sol.value().x_min.x; + } + } +}