TOP > 数学 離散対数問題(Mod-Log) 2019/10/25 • ei1333 説明 与えられた $a, b, p$ に対し $a^x \equiv b \pmod p$ を満たす非負整数 $x$ の最小値を求める。 計算量 $O(\sqrt p)$ 実装例 mod_log($a$, $b$, $p$): $a^x \equiv b \pmod p$ を満たす非負整数 $x$ の最小値を返す。存在しない場合は $-1$。 int64_t mod_log(int64_t a, int64_t b, int64_t p) { int64_t g = 1; for(int64_t i = p; i; i /= 2) (g *= a) %= p; g = __gcd(g, p); int64_t t = 1, c = 0; for(; t % g; c++) { if(t == b) return c; (t *= a) %= p; } if(b % g) return -1; t /= g; b /= g; int64_t n = p / g, h = 0, gs = 1; for(; h * h < n; h++) (gs *= a) %= n; unordered_map< int64_t, int64_t > bs; for(int64_t s = 0, e = b; s < h; bs[e] = ++s) { (e *= a) %= n; } for(int64_t s = 0, e = t; s < n;) { (e *= gs) %= n; s += h; if(bs.count(e)) return c + s - bs[e]; } return -1; } 検証 AtCoder Regular Contest 042 D あまり int64_t power(int64_t x, int64_t n, int64_t mod) { int64_t ret = 1; while(n > 0) { if(n & 1) (ret *= x) %= mod; (x *= x) %= mod; n >>= 1; } return ret; } signed main() { int x, p, a, b; cin >> x >> p >> a >> b; if(p <= a) { int k = a / p; a -= k * p; b -= k * p; } if((b - a + 1) <= 10000000) { int64_t ret = infll; auto tmp = power(x, a, p); for(int i = a; i <= b; i++) { ret = min(ret, tmp); tmp = tmp * x % p; } cout << ret << endl; } else { for(int i = 1;; i++) { int tmp = mod_log(x, i, p); if((a <= tmp && tmp <= b) || (a <= tmp + p && tmp + p <= b)) { cout << i << endl; break; } } } }