This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub ruthen71/rcpl
#include "math/baby_step_giant_step.hpp"
#pragma once #include "math/inv_mod.hpp" #include "math/pow_mod.hpp" // find minimum K s.t. X ^ K = Y (mod M) and K >= lb // O(sqrt(M)) long long baby_step_giant_step(long long X, long long Y, long long M, long long lb = 0LL) { X %= M, Y %= M; if (X < 0) X += M; if (Y < 0) Y += M; if (std::gcd(X, M) != 1) return -1; long long sqM = sqrt(M) + 1; std::unordered_map<long long, long long> mp; // Baby-step long long Z = pow_mod(X, lb, M); // Z = X ^ lb (mod M) for (int i = 0; i < sqM; i++) { if (mp.find(Z) == mp.end()) mp[Z] = i + lb; Z = Z * X % M; } // Z = X ^ sqM (mod M) // R = Z ^ (-1) (mod M) long long R = inv_mod(pow_mod(X, sqM, M), M); // Giant-step for (int i = 0; i <= sqM; i++) { if (mp.find(Y) != mp.end()) return mp[Y] + i * sqM; Y = Y * R % M; } return -1; }
#line 2 "math/baby_step_giant_step.hpp" #line 2 "math/inv_mod.hpp" #include <cassert> #line 2 "math/extended_gcd.hpp" #include <tuple> // find (x, y) s.t. ax + by = gcd(a, b) // a, b >= 0 // return {x, y, gcd(a, b)} template <class T> std::tuple<T, T, T> extended_gcd(T a, T b) { if (b == 0) return {1, 0, a}; auto [y, x, g] = extended_gcd(b, a % b); return {x, y - (a / b) * x, g}; } #line 5 "math/inv_mod.hpp" // mod >= 2 long long inv_mod(long long a, long long mod) { a %= mod; if (a < 0) a += mod; assert(a != 0); auto [x, y, g] = extended_gcd(a, mod); x %= mod; if (x < 0) x += mod; return x; } #line 2 "math/pow_mod.hpp" long long pow_mod(long long a, long long n, const long long mod) { assert(n >= 0 and mod >= 1); if (mod == 1) return 0; a %= mod; if (a < 0) a += mod; long long res = 1; while (n) { if (n & 1) res = res * a % mod; a = a * a % mod; n >>= 1; } return res; } #line 5 "math/baby_step_giant_step.hpp" // find minimum K s.t. X ^ K = Y (mod M) and K >= lb // O(sqrt(M)) long long baby_step_giant_step(long long X, long long Y, long long M, long long lb = 0LL) { X %= M, Y %= M; if (X < 0) X += M; if (Y < 0) Y += M; if (std::gcd(X, M) != 1) return -1; long long sqM = sqrt(M) + 1; std::unordered_map<long long, long long> mp; // Baby-step long long Z = pow_mod(X, lb, M); // Z = X ^ lb (mod M) for (int i = 0; i < sqM; i++) { if (mp.find(Z) == mp.end()) mp[Z] = i + lb; Z = Z * X % M; } // Z = X ^ sqM (mod M) // R = Z ^ (-1) (mod M) long long R = inv_mod(pow_mod(X, sqM, M), M); // Giant-step for (int i = 0; i <= sqM; i++) { if (mp.find(Y) != mp.end()) return mp[Y] + i * sqM; Y = Y * R % M; } return -1; }