cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
gcd.hpp
1#pragma once
2
3#include <cassert>
4#include <tuple>
5#include <type_traits>
6
7#include "cplib/port/bit.hpp"
8
9namespace cplib {
10
20template <typename T, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
21constexpr T gcd(T x, T y) {
22 if (x == 0) {
23 return y;
24 } else if (y == 0) {
25 return x;
26 }
27 int kx = port::countr_zero(x);
28 int ky = port::countr_zero(y);
29 x >>= kx;
30 while (y != 0) {
31 y >>= port::countr_zero(y);
32 if (x > y) {
33 std::swap(x, y);
34 }
35 y -= x;
36 }
37 return x << std::min(kx, ky);
38}
39
57template <typename T, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
58constexpr std::tuple<std::make_signed_t<T>, std::make_signed_t<T>, T> bezout(T x, T y) {
59 bool swap = x < y;
60 if (swap) {
61 std::swap(x, y);
62 }
63 if (y == 0) {
64 if (x == 0) {
65 return {0, 0, 0};
66 } else if (swap) {
67 return {0, 1, x};
68 } else {
69 return {1, 0, x};
70 }
71 }
72 using S = std::make_signed_t<T>;
73 S s0 = 1, s1 = 0, t0 = 0, t1 = 1;
74 while (true) {
75 T q = x / y, r = x % y;
76 if (r == 0) {
77 if (swap) {
78 return {t1, s1, y};
79 } else {
80 return {s1, t1, y};
81 }
82 }
83 S s2 = s0 - S(q) * s1, t2 = t0 - S(q) * t1;
84 x = y;
85 y = r;
86 s0 = s1;
87 s1 = s2;
88 t0 = t1;
89 t1 = t2;
90 }
91}
92
101template <typename T, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
102constexpr T mod_inverse(T x, T m) {
103 auto [s, t, g] = bezout(x, m);
104 assert(g == 1);
105 return s < 0 ? T(s) + m : s;
106}
107
108} // namespace cplib
constexpr T gcd(T x, T y)
Greatest common divisor.
Definition: gcd.hpp:21
constexpr T mod_inverse(T x, T m)
Modular inverse.
Definition: gcd.hpp:102
constexpr std::tuple< std::make_signed_t< T >, std::make_signed_t< T >, T > bezout(T x, T y)
Bézout coefficients, i.e. such that .
Definition: gcd.hpp:58