Baby-Step Giant-Step
Baby-Step Giant-Stepアルゴリズムのまとめ
概要
本記事は(pは素数)を満たすxを求める方法を考える。
アルゴリズム
あると決定する
なるiについて、を計算する。
なるjについて、を計算する。
解xが存在する時、jを増やしてく過程でなるm, nが存在し、
Kの決め方
の列挙を個、の列挙を個行うので、列挙数を最小にするとする
検証
が素数なので、はからの全ての値を1回ずつとる。
を満たすも1つだけ存在し、も1つだけ存在するので、最初に見つけたものを正解として構わない。
例
small step
giant step
よって
実装
#include <iostream> #include <math.h> #include <map> using namespace std; typedef long long ll; map<ll, ll> gn; ll pow(ll g, ll k, ll p) { ll ret = 1; while (k) { if (k&1) (ret *= g) %= p; (g *= g) %= p; k >>= 1; } return ret; } ll inv(ll g, ll p) { // g^{p-2} = g^{-1} return pow(g, p-2, p); } ll babyStepGiantStep(ll p, ll g, ll y) { int k = sqrt(p); // baby step ll gg = 1; for (int i = 0; i < k; i++) { gn[gg] = i; (gg *= g) %= p; } // giant step ll ginv = inv(g, p); ll gk = pow(ginv, k, p); ll yg = 1; int r = p/k; for (ll j = 0; j <= r; j++) { ll yg = y*pow(gk, j, p)%p; if (gn.count(yg) != 0) { return gn[yg] + j * k; } } } int main() { ll p, g, y; cin >> p >> g >> y; cout << babyStepGiantStep(p, g, y) << endl; }
計算量
列挙にそれぞれ、べき乗の計算とmapの検索になので全体で