cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
discrete_log.hpp
1#pragma once
2
3#include <cmath>
4#include <optional>
5#include <unordered_map>
6
7#include "cplib/num/bmint.hpp"
8#include "cplib/num/gcd.hpp"
9#include "cplib/port/bit.hpp"
10
11namespace cplib {
12
13namespace impl {
14
15// g^k=x (mod n)
16template <typename ModInt>
17std::optional<typename ModInt::int_type> discrete_log_coprime_modint(ModInt g, ModInt x) {
18 using T = typename ModInt::int_type;
19 const T n = ModInt::mod(), m = std::ceil(std::sqrt(n));
20 std::unordered_map<T, T> table;
21 ModInt s(1);
22 for (T i = 1; i <= m; i++) {
23 s *= g;
24 table.try_emplace(s.residue(), i);
25 }
26 s = s.inv();
27 for (T i = 0; i < m; i++) {
28 if (auto it = table.find(x.residue()); it != table.end()) {
29 return i * m + it->second;
30 }
31 x *= s;
32 }
33 return std::nullopt;
34}
35
36// Solve y*g^k=x (mod n) naively if k<=t, otherwise return -1 and y*g^t%n.
37template <typename T>
38std::pair<int, T> discrete_log_naive(T g, T x, T n, int t) {
39 if (x == 1) {
40 return {0, x};
41 }
42 using bmint = BarrettModInt<DynamicBarrettReductionContext<T>>;
43 auto _guard = bmint::set_mod_guard(n);
44 bmint mg(g), my(1);
45 for (int i = 1; i <= t; i++) {
46 my *= mg;
47 if (my.val() == x) {
48 return {i, x};
49 }
50 }
51 return {-1, my.val()};
52}
53
54} // namespace impl
55
67template <typename T, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
68std::optional<T> discrete_log(T g, T x, T n) {
69 if (n == 1) {
70 return 0;
71 }
72 const int t = port::bit_width(n) - 1;
73 auto [k, y] = impl::discrete_log_naive(g, x, n, t);
74 if (k >= 0) {
75 return k;
76 }
77 if (y == 0) {
78 return std::nullopt;
79 }
80 T d = gcd(y, n);
81 if (x % d != 0) {
82 return std::nullopt;
83 }
85 auto _guard = mint::set_mod_guard(n / d);
86 if (auto ret = impl::discrete_log_coprime_modint(mint(g), mint(x) / mint(y))) {
87 return ret.value() + t;
88 }
89 return std::nullopt;
90}
91
92} // namespace cplib
Modular integer using Barrett reduction.
Definition: bmint.hpp:111
constexpr T gcd(T x, T y)
Greatest common divisor.
Definition: gcd.hpp:21
std::optional< T > discrete_log(T g, T x, T n)
Modular discrete logarithm.
Definition: discrete_log.hpp:68