This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub suisen-cp/cp-library-cpp
#include "library/number/discrete_logarithm.hpp"
#ifndef SUISEN_DISCRETE_LOGARITHM #define SUISEN_DISCRETE_LOGARITHM #include <cmath> #include <unordered_map> #include <numeric> namespace suisen { namespace internal::discrete_logarithm { int floor_log2(int m) { int res = 0; while (1 << (res + 1) <= m) ++res; return res; } } template <typename mint> int discrete_logarithm_coprime(mint x, mint y) { const int m = mint::mod(); if (y == 1 or m == 1) return 0; if (x == 0) return y == 0 ? 1 : -1; const int p = ::sqrt(m) + 1; mint a = mint(x).inv().pow(p); std::unordered_map<int, int> mp; mint pow_x = 1; for (int j = 0; j < p; ++j, pow_x *= x) mp.try_emplace(pow_x.val(), j); mint ya = y; for (int i = 0; i < p; ++i, ya *= a) { if (auto it = mp.find(ya.val()); it != mp.end()) return p * i + it->second; } return -1; } template <typename mint> int discrete_logarithm(mint x, mint y) { using namespace internal::discrete_logarithm; const int m = mint::mod(); if (m == 1) return 0; const int d = floor_log2(m); mint pow_x = 1; for (int i = 0; i < d; ++i, pow_x *= x) if (pow_x == y) return i; const int g = std::gcd(pow_x.val(), m); if (y.val() % g) return -1; mint::set_mod(m / g); const int t = discrete_logarithm_coprime(mint(x.val()), mint(y.val()) * mint(pow_x.val()).inv()); mint::set_mod(m); return t != -1 ? d + t : -1; } } // namespace suisen #endif // SUISEN_DISCRETE_LOGARITHM
#line 1 "library/number/discrete_logarithm.hpp" #include <cmath> #include <unordered_map> #include <numeric> namespace suisen { namespace internal::discrete_logarithm { int floor_log2(int m) { int res = 0; while (1 << (res + 1) <= m) ++res; return res; } } template <typename mint> int discrete_logarithm_coprime(mint x, mint y) { const int m = mint::mod(); if (y == 1 or m == 1) return 0; if (x == 0) return y == 0 ? 1 : -1; const int p = ::sqrt(m) + 1; mint a = mint(x).inv().pow(p); std::unordered_map<int, int> mp; mint pow_x = 1; for (int j = 0; j < p; ++j, pow_x *= x) mp.try_emplace(pow_x.val(), j); mint ya = y; for (int i = 0; i < p; ++i, ya *= a) { if (auto it = mp.find(ya.val()); it != mp.end()) return p * i + it->second; } return -1; } template <typename mint> int discrete_logarithm(mint x, mint y) { using namespace internal::discrete_logarithm; const int m = mint::mod(); if (m == 1) return 0; const int d = floor_log2(m); mint pow_x = 1; for (int i = 0; i < d; ++i, pow_x *= x) if (pow_x == y) return i; const int g = std::gcd(pow_x.val(), m); if (y.val() % g) return -1; mint::set_mod(m / g); const int t = discrete_logarithm_coprime(mint(x.val()), mint(y.val()) * mint(pow_x.val()).inv()); mint::set_mod(m); return t != -1 ? d + t : -1; } } // namespace suisen