Problem p03969 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
using Int = long long;
template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}

template <typename T, T MOD = 1000000007> struct Mint {
  T v;
  Mint() : v(0) {}
  Mint(signed v) : v(v) {}
  Mint(long long t) {
    v = t % MOD;
    if (v < 0)
      v += MOD;
  }

  Mint pow(long long k) {
    Mint res(1), tmp(v);
    while (k) {
      if (k & 1)
        res *= tmp;
      tmp *= tmp;
      k >>= 1;
    }
    return res;
  }

  static Mint add_identity() { return Mint(0); }
  static Mint mul_identity() { return Mint(1); }

  Mint inv() { return pow(MOD - 2); }

  Mint &operator+=(Mint a) {
    v += a.v;
    if (v >= MOD)
      v -= MOD;
    return *this;
  }
  Mint &operator-=(Mint a) {
    v += MOD - a.v;
    if (v >= MOD)
      v -= MOD;
    return *this;
  }
  Mint &operator*=(Mint a) {
    v = 1LL * v * a.v % MOD;
    return *this;
  }
  Mint &operator/=(Mint a) { return (*this) *= a.inv(); }

  Mint operator+(Mint a) const { return Mint(v) += a; };
  Mint operator-(Mint a) const { return Mint(v) -= a; };
  Mint operator*(Mint a) const { return Mint(v) *= a; };
  Mint operator/(Mint a) const { return Mint(v) /= a; };

  Mint operator-() const { return v ? Mint(MOD - v) : Mint(v); }

  bool operator==(const Mint a) const { return v == a.v; }
  bool operator!=(const Mint a) const { return v != a.v; }
  bool operator<(const Mint a) const { return v < a.v; }

  // find x s.t. a^x = b
  static T log(T a, T b) {
    const T sq = 40000;
    unordered_map<T, T> dp;
    dp.reserve(sq);
    Mint res(1);
    for (Int r = 0; r < sq; r++) {
      if (!dp.count(res.v))
        dp[res.v] = r;
      res *= a;
    }
    Mint p = Mint(a).inv().pow(sq);
    res = b;
    for (Int q = 0; q <= MOD / sq + 1; q++) {
      if (dp.count(res.v)) {
        T idx = q * sq + dp[res.v];
        if (idx > 0)
          return idx;
      }
      res *= p;
    }
    assert(0);
    return T(-1);
  }

  static Mint comb(long long n, Int k) {
    Mint num(1), dom(1);
    for (Int i = 0; i < k; i++) {
      num *= Mint(n - i);
      dom *= Mint(i + 1);
    }
    return num / dom;
  }
};

template <typename M> struct Enumeration {
  static vector<M> fact, finv, invs;

  static void init(Int n) {
    Int m = fact.size();
    if (n < m)
      return;

    fact.resize(n + 1, 1);
    finv.resize(n + 1, 1);
    invs.resize(n + 1, 1);

    if (m == 0)
      m = 1;
    for (Int i = m; i <= n; i++)
      fact[i] = fact[i - 1] * M(i);
    finv[n] = M(1) / fact[n];
    for (Int i = n; i >= m; i--)
      finv[i - 1] = finv[i] * M(i);
    for (Int i = m; i <= n; i++)
      invs[i] = finv[i] * fact[i - 1];
  }

  static M C(Int n, Int k) {
    if (n < k || k < 0)
      return M(0);
    init(n);
    return fact[n] * finv[n - k] * finv[k];
  }

  static M P(Int n, Int k) {
    if (n < k || k < 0)
      return M(0);
    init(n);
    return fact[n] * finv[n - k];
  }

  static M H(Int n, Int k) {
    if (n < 0 || k < 0)
      return M(0);
    if (!n && !k)
      return M(1);
    init(n + k - 1);
    return C(n + k - 1, k);
  }

  static M S(Int n, Int k) {
    M res;
    init(k);
    for (Int i = 1; i <= k; i++) {
      M tmp = C(k, i) * M(i).pow(n);
      if ((k - i) & 1)
        res -= tmp;
      else
        res += tmp;
    }
    return res *= finv[k];
  }

  static vector<vector<M>> D(Int n, Int m) {
    vector<vector<M>> dp(n + 1, vector<M>(m + 1, 0));
    dp[0][0] = M(1);
    for (Int i = 0; i <= n; i++) {
      for (Int j = 1; j <= m; j++) {
        if (i - j >= 0)
          dp[i][j] = dp[i][j - 1] + dp[i - j][j];
        else
          dp[i][j] = dp[i][j - 1];
      }
    }
    return dp;
  }

  static M B(Int n, Int k) {
    if (n == 0)
      return M(1);
    k = min(k, n);
    init(k);
    vector<M> dp(k + 1);
    dp[0] = M(1);
    for (Int i = 1; i <= k; i++)
      dp[i] = dp[i - 1] + ((i & 1) ? -finv[i] : finv[i]);
    M res;
    for (Int i = 1; i <= k; i++)
      res += M(i).pow(n) * finv[i] * dp[k - i];
    return res;
  }

  static M montmort(Int n) {
    M res;
    init(n);
    for (Int k = 2; k <= n; k++) {
      if (k & 1)
        res -= finv[k];
      else
        res += finv[k];
    }
    return res *= fact[n];
  }

  static M LagrangePolynomial(vector<M> &y, M t) {
    Int n = y.size() - 1;
    if (t.v <= n)
      return y[t.v];
    init(n + 1);
    M num(1);
    for (Int i = 0; i <= n; i++)
      num *= t - M(i);
    M res;
    for (Int i = 0; i <= n; i++) {
      M tmp = y[i] * num / (t - M(i)) * finv[i] * finv[n - i];
      if ((n - i) & 1)
        res -= tmp;
      else
        res += tmp;
    }
    return res;
  }
};
template <typename M> vector<M> Enumeration<M>::fact = vector<M>();
template <typename M> vector<M> Enumeration<M>::finv = vector<M>();
template <typename M> vector<M> Enumeration<M>::invs = vector<M>();

struct UnionFind {
  Int n, num;
  vector<Int> r, p;
  UnionFind() {}
  UnionFind(Int sz) : n(sz), num(sz), r(sz, 1), p(sz, 0) {
    iota(p.begin(), p.end(), 0);
  }
  Int find(Int x) { return (x == p[x] ? x : p[x] = find(p[x])); }
  bool same(Int x, Int y) { return find(x) == find(y); }
  void unite(Int x, Int y) {
    x = find(x);
    y = find(y);
    if (x == y)
      return;
    if (r[x] < r[y])
      swap(x, y);
    r[x] += r[y];
    p[y] = x;
    num--;
  }
  Int size(Int x) { return r[find(x)]; }
  Int count() const { return num; }
};

struct BiconnectedComponent {
  vector<Int> ord, low;
  vector<bool> used;
  vector<vector<Int>> g;
  vector<vector<pair<Int, Int>>> bc;
  vector<pair<Int, Int>> tmp;
  Int n, k = 0;
  BiconnectedComponent(const vector<vector<Int>> &g) : g(g) {
    n = g.size();
    ord.resize(n, -1);
    low.resize(n, -1);
    used.resize(n, false);
  }
  void dfs(Int u, Int prev) {
    used[u] = true;
    ord[u] = k++;
    low[u] = ord[u];
    Int cnt = 0;
    for (auto v : g[u])
      if (v != prev) {
        if (ord[v] < ord[u]) {
          tmp.emplace_back(min(u, v), max(u, v));
        }
        if (!used[v]) {
          cnt++;
          dfs(v, u);
          low[u] = min(low[u], low[v]);
          if (low[v] >= ord[u]) {
            bc.push_back({});
            while (true) {
              pair<Int, Int> e = tmp.back();
              bc.back().emplace_back(e);
              tmp.pop_back();
              if (min(u, v) == e.first && max(u, v) == e.second) {
                break;
              }
            }
          }
        } else {
          low[u] = min(low[u], ord[v]);
        }
      }
  }
};
template <typename F> struct FixPoint : F {
  FixPoint(F &&f) : F(forward<F>(f)) {}
  template <typename... Args> decltype(auto) operator()(Args &&...args) const {
    return F::operator()(*this, forward<Args>(args)...);
  }
};
template <typename F> inline decltype(auto) MFP(F &&f) {
  return FixPoint<F>{forward<F>(f)};
}

// INSERT ABOVE HERE
signed main() {
  Int n, m, k;
  cin >> n >> m >> k;

  using P = pair<Int, Int>;
  map<P, Int> idx;
  vector<vector<Int>> G(n);
  for (Int i = 0; i < m; i++) {
    Int a, b;
    cin >> a >> b;
    a--;
    b--;
    G[a].emplace_back(b);
    G[b].emplace_back(a);
    idx[P(a, b)] = idx[P(b, a)] = i;
  }

  BiconnectedComponent bc(G);
  for (Int i = 0; i < n; i++) {
    if (bc.used[i])
      continue;
    bc.dfs(i, -1);
  }

  UnionFind uf(m);
  for (auto vs : bc.bc)
    for (auto p : vs)
      uf.unite(idx[p], idx[vs[0]]);

  vector<set<Int>> cnt(m);
  for (auto vs : bc.bc) {
    for (auto p : vs) {
      cnt[uf.find(idx[p])].emplace(p.first);
      cnt[uf.find(idx[p])].emplace(p.second);
    }
  }

  using M = Mint<Int>;
  using E = Enumeration<M>;
  E::init(1e5);

  vector<M> dp1(n + 1), dp2(n + 1);
  vector<Int> used1(n + 1, 0), used2(n + 1, 0);

  auto calc1 = [&](Int x) -> M {
    if (used1[x])
      return dp1[x];
    used1[x] = 1;
    M &res = dp1[x];
    res = M(0);

    for (Int i = 0; i < x; i++)
      res += M(k).pow(__gcd(i, x));

    res *= E::invs[x];
    return res;
  };

  auto calc2 = MFP([&](auto dfs, Int x) -> M {
    if (x == 0)
      return M(1);
    if (used2[x])
      return dp2[x];
    used2[x] = 1;
    M &res = dp2[x];
    res = M(0);

    for (Int l = 1; l <= x; l++)
      res += M(k) * dfs(x - l);

    res *= E::invs[x];
    return res;
  });

  M ans{1};
  for (Int i = 0; i < m; i++) {
    if (uf.find(i) != i)
      continue;
    if (uf.size(i) < (Int)cnt[i].size())
      ans *= M(k).pow(uf.size(i));
    if (uf.size(i) == (Int)cnt[i].size())
      ans *= calc1(uf.size(i));
    if (uf.size(i) > (Int)cnt[i].size())
      ans *= calc2(uf.size(i));
  }
  cout << ans.v << endl;
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
using namespace std;
using Int = long long;
template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}

template <typename T, T MOD = 1000000007> struct Mint {
  T v;
  Mint() : v(0) {}
  Mint(signed v) : v(v) {}
  Mint(long long t) {
    v = t % MOD;
    if (v < 0)
      v += MOD;
  }

  Mint pow(long long k) {
    Mint res(1), tmp(v);
    while (k) {
      if (k & 1)
        res *= tmp;
      tmp *= tmp;
      k >>= 1;
    }
    return res;
  }

  static Mint add_identity() { return Mint(0); }
  static Mint mul_identity() { return Mint(1); }

  Mint inv() { return pow(MOD - 2); }

  Mint &operator+=(Mint a) {
    v += a.v;
    if (v >= MOD)
      v -= MOD;
    return *this;
  }
  Mint &operator-=(Mint a) {
    v += MOD - a.v;
    if (v >= MOD)
      v -= MOD;
    return *this;
  }
  Mint &operator*=(Mint a) {
    v = 1LL * v * a.v % MOD;
    return *this;
  }
  Mint &operator/=(Mint a) { return (*this) *= a.inv(); }

  Mint operator+(Mint a) const { return Mint(v) += a; };
  Mint operator-(Mint a) const { return Mint(v) -= a; };
  Mint operator*(Mint a) const { return Mint(v) *= a; };
  Mint operator/(Mint a) const { return Mint(v) /= a; };

  Mint operator-() const { return v ? Mint(MOD - v) : Mint(v); }

  bool operator==(const Mint a) const { return v == a.v; }
  bool operator!=(const Mint a) const { return v != a.v; }
  bool operator<(const Mint a) const { return v < a.v; }

  // find x s.t. a^x = b
  static T log(T a, T b) {
    const T sq = 40000;
    unordered_map<T, T> dp;
    dp.reserve(sq);
    Mint res(1);
    for (Int r = 0; r < sq; r++) {
      if (!dp.count(res.v))
        dp[res.v] = r;
      res *= a;
    }
    Mint p = Mint(a).inv().pow(sq);
    res = b;
    for (Int q = 0; q <= MOD / sq + 1; q++) {
      if (dp.count(res.v)) {
        T idx = q * sq + dp[res.v];
        if (idx > 0)
          return idx;
      }
      res *= p;
    }
    assert(0);
    return T(-1);
  }

  static Mint comb(long long n, Int k) {
    Mint num(1), dom(1);
    for (Int i = 0; i < k; i++) {
      num *= Mint(n - i);
      dom *= Mint(i + 1);
    }
    return num / dom;
  }
};

template <typename M> struct Enumeration {
  static vector<M> fact, finv, invs;

  static void init(Int n) {
    Int m = fact.size();
    if (n < m)
      return;

    fact.resize(n + 1, 1);
    finv.resize(n + 1, 1);
    invs.resize(n + 1, 1);

    if (m == 0)
      m = 1;
    for (Int i = m; i <= n; i++)
      fact[i] = fact[i - 1] * M(i);
    finv[n] = M(1) / fact[n];
    for (Int i = n; i >= m; i--)
      finv[i - 1] = finv[i] * M(i);
    for (Int i = m; i <= n; i++)
      invs[i] = finv[i] * fact[i - 1];
  }

  static M C(Int n, Int k) {
    if (n < k || k < 0)
      return M(0);
    init(n);
    return fact[n] * finv[n - k] * finv[k];
  }

  static M P(Int n, Int k) {
    if (n < k || k < 0)
      return M(0);
    init(n);
    return fact[n] * finv[n - k];
  }

  static M H(Int n, Int k) {
    if (n < 0 || k < 0)
      return M(0);
    if (!n && !k)
      return M(1);
    init(n + k - 1);
    return C(n + k - 1, k);
  }

  static M S(Int n, Int k) {
    M res;
    init(k);
    for (Int i = 1; i <= k; i++) {
      M tmp = C(k, i) * M(i).pow(n);
      if ((k - i) & 1)
        res -= tmp;
      else
        res += tmp;
    }
    return res *= finv[k];
  }

  static vector<vector<M>> D(Int n, Int m) {
    vector<vector<M>> dp(n + 1, vector<M>(m + 1, 0));
    dp[0][0] = M(1);
    for (Int i = 0; i <= n; i++) {
      for (Int j = 1; j <= m; j++) {
        if (i - j >= 0)
          dp[i][j] = dp[i][j - 1] + dp[i - j][j];
        else
          dp[i][j] = dp[i][j - 1];
      }
    }
    return dp;
  }

  static M B(Int n, Int k) {
    if (n == 0)
      return M(1);
    k = min(k, n);
    init(k);
    vector<M> dp(k + 1);
    dp[0] = M(1);
    for (Int i = 1; i <= k; i++)
      dp[i] = dp[i - 1] + ((i & 1) ? -finv[i] : finv[i]);
    M res;
    for (Int i = 1; i <= k; i++)
      res += M(i).pow(n) * finv[i] * dp[k - i];
    return res;
  }

  static M montmort(Int n) {
    M res;
    init(n);
    for (Int k = 2; k <= n; k++) {
      if (k & 1)
        res -= finv[k];
      else
        res += finv[k];
    }
    return res *= fact[n];
  }

  static M LagrangePolynomial(vector<M> &y, M t) {
    Int n = y.size() - 1;
    if (t.v <= n)
      return y[t.v];
    init(n + 1);
    M num(1);
    for (Int i = 0; i <= n; i++)
      num *= t - M(i);
    M res;
    for (Int i = 0; i <= n; i++) {
      M tmp = y[i] * num / (t - M(i)) * finv[i] * finv[n - i];
      if ((n - i) & 1)
        res -= tmp;
      else
        res += tmp;
    }
    return res;
  }
};
template <typename M> vector<M> Enumeration<M>::fact = vector<M>();
template <typename M> vector<M> Enumeration<M>::finv = vector<M>();
template <typename M> vector<M> Enumeration<M>::invs = vector<M>();

struct UnionFind {
  Int n, num;
  vector<Int> r, p;
  UnionFind() {}
  UnionFind(Int sz) : n(sz), num(sz), r(sz, 1), p(sz, 0) {
    iota(p.begin(), p.end(), 0);
  }
  Int find(Int x) { return (x == p[x] ? x : p[x] = find(p[x])); }
  bool same(Int x, Int y) { return find(x) == find(y); }
  void unite(Int x, Int y) {
    x = find(x);
    y = find(y);
    if (x == y)
      return;
    if (r[x] < r[y])
      swap(x, y);
    r[x] += r[y];
    p[y] = x;
    num--;
  }
  Int size(Int x) { return r[find(x)]; }
  Int count() const { return num; }
};

struct BiconnectedComponent {
  vector<Int> ord, low;
  vector<bool> used;
  vector<vector<Int>> g;
  vector<vector<pair<Int, Int>>> bc;
  vector<pair<Int, Int>> tmp;
  Int n, k = 0;
  BiconnectedComponent(const vector<vector<Int>> &g) : g(g) {
    n = g.size();
    ord.resize(n, -1);
    low.resize(n, -1);
    used.resize(n, false);
  }
  void dfs(Int u, Int prev) {
    used[u] = true;
    ord[u] = k++;
    low[u] = ord[u];
    Int cnt = 0;
    for (auto v : g[u])
      if (v != prev) {
        if (ord[v] < ord[u]) {
          tmp.emplace_back(min(u, v), max(u, v));
        }
        if (!used[v]) {
          cnt++;
          dfs(v, u);
          low[u] = min(low[u], low[v]);
          if (low[v] >= ord[u]) {
            bc.push_back({});
            while (true) {
              pair<Int, Int> e = tmp.back();
              bc.back().emplace_back(e);
              tmp.pop_back();
              if (min(u, v) == e.first && max(u, v) == e.second) {
                break;
              }
            }
          }
        } else {
          low[u] = min(low[u], ord[v]);
        }
      }
  }
};
template <typename F> struct FixPoint : F {
  FixPoint(F &&f) : F(forward<F>(f)) {}
  template <typename... Args> decltype(auto) operator()(Args &&...args) const {
    return F::operator()(*this, forward<Args>(args)...);
  }
};
template <typename F> inline decltype(auto) MFP(F &&f) {
  return FixPoint<F>{forward<F>(f)};
}

// INSERT ABOVE HERE
signed main() {
  Int n, m, k;
  cin >> n >> m >> k;

  using P = pair<Int, Int>;
  map<P, Int> idx;
  vector<vector<Int>> G(n);
  for (Int i = 0; i < m; i++) {
    Int a, b;
    cin >> a >> b;
    a--;
    b--;
    G[a].emplace_back(b);
    G[b].emplace_back(a);
    idx[P(a, b)] = idx[P(b, a)] = i;
  }

  BiconnectedComponent bc(G);
  for (Int i = 0; i < n; i++) {
    if (bc.used[i])
      continue;
    bc.dfs(i, -1);
  }

  UnionFind uf(m);
  for (auto vs : bc.bc)
    for (auto p : vs)
      uf.unite(idx[p], idx[vs[0]]);

  vector<set<Int>> cnt(m);
  for (auto vs : bc.bc) {
    for (auto p : vs) {
      cnt[uf.find(idx[p])].emplace(p.first);
      cnt[uf.find(idx[p])].emplace(p.second);
    }
  }

  using M = Mint<Int>;
  using E = Enumeration<M>;
  E::init(1e5);

  vector<M> dp1(m + 1), dp2(m + 1);
  vector<Int> used1(m + 1, 0), used2(m + 1, 0);

  auto calc1 = [&](Int x) -> M {
    if (used1[x])
      return dp1[x];
    used1[x] = 1;
    M &res = dp1[x];
    res = M(0);

    for (Int i = 0; i < x; i++)
      res += M(k).pow(__gcd(i, x));

    res *= E::invs[x];
    return res;
  };

  auto calc2 = MFP([&](auto dfs, Int x) -> M {
    if (x == 0)
      return M(1);
    if (used2[x])
      return dp2[x];
    used2[x] = 1;
    M &res = dp2[x];
    res = M(0);

    for (Int l = 1; l <= x; l++)
      res += M(k) * dfs(x - l);

    res *= E::invs[x];
    return res;
  });

  M ans{1};
  for (Int i = 0; i < m; i++) {
    if (uf.find(i) != i)
      continue;
    if (uf.size(i) < (Int)cnt[i].size())
      ans *= M(k).pow(uf.size(i));
    if (uf.size(i) == (Int)cnt[i].size())
      ans *= calc1(uf.size(i));
    if (uf.size(i) > (Int)cnt[i].size())
      ans *= calc2(uf.size(i));
  }
  cout << ans.v << endl;
  return 0;
}