library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub maspypy/library

:heavy_check_mark: nt/discrete_log.hpp

Depends on

Required by

Verified with

Code

#include "alg/monoid/mul.hpp"

#include "alg/acted_set/from_monoid.hpp"

#include "ds/hashmap.hpp"


// モノイド X の作用する集合 S、ハッシュ関数 H:S -> Z

// x in X, s, t in S に対して x^ns = t を解く

// [lb, ub) の最初の解をかえす。なければ -1 をかえす。

template <typename ActedSet, typename F>
ll discrete_log_acted(typename ActedSet::A x, typename ActedSet::S s,
                      typename ActedSet::S t, F H, ll lb, ll ub) {
  using Mono = typename ActedSet::Monoid_A;
  using X = typename Mono::value_type;
  using S = typename ActedSet::S;

  if (lb >= ub) return -1;
  auto xpow = [&](ll n) -> X {
    X p = x;
    X res = Mono::unit();
    while (n) {
      if (n & 1) res = Mono::op(res, p);
      p = Mono::op(p, p);
      n /= 2;
    }
    return res;
  };

  auto Ht = H(t);
  s = ActedSet::act(s, xpow(lb));
  u64 LIM = ub - lb;

  ll K = sqrt(LIM) + 1;

  HashMap<char> MP(K);

  FOR(k, K) {
    t = ActedSet::act(t, x);
    MP[H(t)] = 1;
  }

  X y = xpow(K);
  int failed = 0;
  FOR(k, K + 1) {
    S s1 = ActedSet::act(s, y);
    if (MP.count(H(s1))) {
      FOR(i, K) {
        if (H(s) == Ht) {
          ll ans = k * K + i + lb;
          return (ans >= ub ? -1 : ans);
        }
        s = ActedSet::act(s, x);
      }
      if (failed) return -1;
      failed = 1;
    }
    s = s1;
  }
  return -1;
}

// 群 X における log_a b の計算

// ハッシュ関数 H : X -> long long を持たせる

// [lb, ub) の最初の解をかえす、なければ -1

template <typename Monoid, typename F>
ll discrete_log_monoid(typename Monoid::X a, typename Monoid::X b, F H, ll lb,
                       ll ub) {
  using AM = ActedSet_From_Monoid<Monoid>;
  return discrete_log_acted<AM>(a, Monoid::unit(), b, H, lb, ub);
}
#line 2 "alg/monoid/mul.hpp"

template <class T>
struct Monoid_Mul {
  using value_type = T;
  using X = T;
  static constexpr X op(const X &x, const X &y) noexcept { return x * y; }
  static constexpr X inverse(const X &x) noexcept { return X(1) / x; }
  static constexpr X unit() { return X(1); }
  static constexpr bool commute = true;
};
#line 1 "alg/acted_set/from_monoid.hpp"
template <typename Monoid>
struct ActedSet_From_Monoid {
  using Monoid_A = Monoid;
  using A = typename Monoid::value_type;
  using S = A;
  static S act(const S &x, const A &g) { return Monoid::op(x, g); }
};
#line 2 "ds/hashmap.hpp"

// u64 -> Val

template <typename Val>
struct HashMap {
  // n は入れたいものの個数で ok

  HashMap(u32 n = 0) { build(n); }
  void build(u32 n) {
    u32 k = 8;
    while (k < n * 2) k *= 2;
    cap = k / 2, mask = k - 1;
    key.resize(k), val.resize(k), used.assign(k, 0);
  }

  // size を保ったまま. size=0 にするときは build すること.

  void clear() {
    used.assign(len(used), 0);
    cap = (mask + 1) / 2;
  }
  int size() { return len(used) / 2 - cap; }

  int index(const u64& k) {
    int i = 0;
    for (i = hash(k); used[i] && key[i] != k; i = (i + 1) & mask) {}
    return i;
  }

  Val& operator[](const u64& k) {
    if (cap == 0) extend();
    int i = index(k);
    if (!used[i]) { used[i] = 1, key[i] = k, val[i] = Val{}, --cap; }
    return val[i];
  }

  Val get(const u64& k, Val default_value) {
    int i = index(k);
    return (used[i] ? val[i] : default_value);
  }

  bool count(const u64& k) {
    int i = index(k);
    return used[i] && key[i] == k;
  }

  // f(key, val)

  template <typename F>
  void enumerate_all(F f) {
    FOR(i, len(used)) if (used[i]) f(key[i], val[i]);
  }

private:
  u32 cap, mask;
  vc<u64> key;
  vc<Val> val;
  vc<bool> used;

  u64 hash(u64 x) {
    static const u64 FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count();
    x += FIXED_RANDOM;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return (x ^ (x >> 31)) & mask;
  }

  void extend() {
    vc<pair<u64, Val>> dat;
    dat.reserve(len(used) / 2 - cap);
    FOR(i, len(used)) {
      if (used[i]) dat.eb(key[i], val[i]);
    }
    build(2 * len(dat));
    for (auto& [a, b]: dat) (*this)[a] = b;
  }
};
#line 4 "nt/discrete_log.hpp"

// モノイド X の作用する集合 S、ハッシュ関数 H:S -> Z

// x in X, s, t in S に対して x^ns = t を解く

// [lb, ub) の最初の解をかえす。なければ -1 をかえす。

template <typename ActedSet, typename F>
ll discrete_log_acted(typename ActedSet::A x, typename ActedSet::S s,
                      typename ActedSet::S t, F H, ll lb, ll ub) {
  using Mono = typename ActedSet::Monoid_A;
  using X = typename Mono::value_type;
  using S = typename ActedSet::S;

  if (lb >= ub) return -1;
  auto xpow = [&](ll n) -> X {
    X p = x;
    X res = Mono::unit();
    while (n) {
      if (n & 1) res = Mono::op(res, p);
      p = Mono::op(p, p);
      n /= 2;
    }
    return res;
  };

  auto Ht = H(t);
  s = ActedSet::act(s, xpow(lb));
  u64 LIM = ub - lb;

  ll K = sqrt(LIM) + 1;

  HashMap<char> MP(K);

  FOR(k, K) {
    t = ActedSet::act(t, x);
    MP[H(t)] = 1;
  }

  X y = xpow(K);
  int failed = 0;
  FOR(k, K + 1) {
    S s1 = ActedSet::act(s, y);
    if (MP.count(H(s1))) {
      FOR(i, K) {
        if (H(s) == Ht) {
          ll ans = k * K + i + lb;
          return (ans >= ub ? -1 : ans);
        }
        s = ActedSet::act(s, x);
      }
      if (failed) return -1;
      failed = 1;
    }
    s = s1;
  }
  return -1;
}

// 群 X における log_a b の計算

// ハッシュ関数 H : X -> long long を持たせる

// [lb, ub) の最初の解をかえす、なければ -1

template <typename Monoid, typename F>
ll discrete_log_monoid(typename Monoid::X a, typename Monoid::X b, F H, ll lb,
                       ll ub) {
  using AM = ActedSet_From_Monoid<Monoid>;
  return discrete_log_acted<AM>(a, Monoid::unit(), b, H, lb, ub);
}
Back to top page