Solve for . Believed hard in general — which is exactly why Diffie-Hellman and ElGamal are built on it.

Baby-step giant-step —

Write with and . Then

Precompute all in a hash table (baby steps), then try each (giant steps).

// smallest x >= 0 with a^x = b (mod m); requires gcd(a, m) = 1
long long bsgs(long long a, long long b, long long m) {
    a %= m; b %= m;
    long long n = (long long)sqrtl((long double)m) + 1;
    unordered_map<long long,long long> vals;
    long long cur = b;
    for (long long q = 0; q <= n; q++) {              // baby steps: b * a^q
        vals[cur] = q;
        cur = cur * a % m;
    }
    long long an = powmod(a, n, m);
    cur = 1;
    for (long long p = 1; p <= n; p++) {              // giant steps: a^(n*p)
        cur = cur * an % m;
        auto it = vals.find(cur);
        if (it != vals.end()) {
            long long x = n * p - it->second;
            if (x >= 0) return x;
        }
    }
    return -1;
}

Insert baby steps in increasing so that overwriting keeps the smallest exponent, giving the minimal .

Cost: time and memory. The memory is the binding constraint for .

When

Divide out the common factor repeatedly:

long long bsgsGeneral(long long a, long long b, long long m) {
    long long g, k = 0, add = 1;
    while ((g = __gcd(a, m)) > 1) {
        if (b == add) return k;
        if (b % g) return -1;                          // no solution
        b /= g; m /= g; add = add * (a / g) % m;
        k++;
    }
    long long r = bsgs(a, b * modinv(add, m) % m, m);
    return r == -1 ? -1 : r + k;
}

Each step removes a prime factor shared by and , so the loop runs times.

The method table

MethodTimeSpaceRequires
Brute forcenothing
Baby-step giant-stepnothing
Pollard’s kangaroo in a known interval
Pollard’s rho for DLPnothing
Pohlig-Hellmansmall smooth
Index calculussub-exponentiallarge only

Pohlig-Hellman is the important one: if the group order factors into small primes, the discrete log becomes easy. This is why cryptographic groups always use a prime or near-prime order.

Uses in competitive programming

ProblemFormulation
directly
Find the period of a sequence order of
“After how many steps does the state repeat?“discrete log in a cyclic structure
discrete root — reduce via a primitive root
Solve a linear recurrence’s periodorder of the transition matrix
Matrix discrete log BSGS with matrix multiplication and hashing

The matrix generalisation is worth knowing: BSGS works in any group where you can multiply and hash elements, so for matrices is solvable in by the identical algorithm.

Practical notes

  • Use a fast hash map (gp_hash_table or a hand-rolled open-addressing table) — unordered_map with insertions is often the bottleneck, and its default hash is hackable.
  • Sorting a vector and binary searching is a fine alternative: but with a much smaller constant and better memory behaviour.
  • Watch for (answer 0) and as special cases.

See also: Primitive Root · Pohlig-Hellman · Pollard Kangaroo