Problem p03492 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;

struct Centroid {
  vector<int> centroid;
  vector<int> sz;
  int N;

  void dfs(int i, int prev, const vector<int> G[]) {
    sz[i] = 1;
    bool is_centroid = true;
    for (auto j : G[i]) {
      if (j == prev)
        continue;
      dfs(j, i, G);
      sz[i] += sz[j];
      if (sz[j] > N / 2)
        is_centroid = false;
    }
    if (N - sz[i] > N / 2)
      is_centroid = false;
    if (is_centroid)
      centroid.push_back(i);
  }

  vector<int> calculate(int Nin, const vector<int> G[]) {
    N = Nin;
    sz.resize(N);
    dfs(0, -1, G);
    return centroid;
  }

  vector<int> partsize(const vector<int> G[]) {
    int c = centroid[0];
    vector<int> ret;
    int rest = N - 1;
    for (auto i : G[c]) {
      if (sz[i] < sz[c]) {
        ret.push_back(sz[i]);
        rest -= sz[i];
      }
    }
    if (rest > 0)
      ret.push_back(rest);
    return ret;
  }
};

const long long FACT_MAX = 5000;
long long famod[FACT_MAX + 1];
long long simod[FACT_MAX + 1];
long long fimod[FACT_MAX + 1];

const long long MOD = 1e9 + 7;

void create_fact_mod(int num) {
  famod[0] = 1;
  famod[1] = 1;
  for (int i = 2; i <= num; i++) {
    famod[i] = famod[i - 1] * i % MOD;
  }
}

void create_seq_inv_mod(int num) {
  simod[0] = 1;
  simod[1] = 1;
  for (int i = 2; i <= num; i++) {
    simod[i] = (MOD - MOD / i) * simod[MOD % i] % MOD;
  }
}

void create_fact_inv_mod(int num) {
  fimod[0] = 1;
  fimod[1] = 1;
  for (int i = 2; i <= num; i++) {
    fimod[i] = fimod[i - 1] * simod[i] % MOD;
  }
}

void create_mod_tables(int num) {
  create_fact_mod(num);
  create_seq_inv_mod(num);
  create_fact_inv_mod(num);
}

long long comb_mod(int n, int k) {
  return famod[n] * fimod[n - k] % MOD * fimod[k] % MOD;
}

long long perm_mod(int n, int k) { return famod[n] * fimod[n - k] % MOD; }

void add(long long &a, long long b) { a = (a + b + MOD) % MOD; }

int main() {
  long long i, j, k;
  int N;
  const int MAX = 500;
  vector<int> edges[MAX];

  cin >> N;
  for (i = 0; i < N - 1; i++) {
    int x, y;
    cin >> x >> y;
    edges[x - 1].push_back(y - 1);
    edges[y - 1].push_back(x - 1);
  }

  Centroid ctr;
  auto centroid = ctr.calculate(N, edges);

  if (centroid.size() == 2) {
    long long ans = 1;
    for (i = 2; i <= N / 2; i++) {
      ans = ans * i * i % MOD;
    }
    cout << ans << endl;
    return 0;
  }

  auto partsize = ctr.partsize(edges);
  int K = partsize.size();
  long long dp[MAX][MAX + 1] = {0};
  dp[0][0] = 1;
  create_mod_tables(N);
  int sum = 0;

  for (i = 0; i < K; i++) {
    int ps = partsize[i];
    for (j = 0; j <= sum; j++) {
      for (k = 0; k <= ps; k++) {
        long long a = dp[i][j] * comb_mod(ps, k) % MOD * comb_mod(ps, k) % MOD *
                      famod[k] % MOD;
        add(dp[i + 1][j + k], a);
      }
    }
    sum += partsize[i];
  }

  long long ans = 0;
  for (i = 0; i <= N - 1; i++) {
    long long a = famod[N - i] * dp[K][i] * (i % 2 == 0 ? 1 : -1) % MOD;
    add(ans, a);
  }
  cout << ans << endl;
  return 0;
}

Fixed submission:
#include <bits/stdc++.h>
using namespace std;

struct Centroid {
  vector<int> centroid;
  vector<int> sz;
  int N;

  void dfs(int i, int prev, const vector<int> G[]) {
    sz[i] = 1;
    bool is_centroid = true;
    for (auto j : G[i]) {
      if (j == prev)
        continue;
      dfs(j, i, G);
      sz[i] += sz[j];
      if (sz[j] > N / 2)
        is_centroid = false;
    }
    if (N - sz[i] > N / 2)
      is_centroid = false;
    if (is_centroid)
      centroid.push_back(i);
  }

  vector<int> calculate(int Nin, const vector<int> G[]) {
    N = Nin;
    sz.resize(N);
    dfs(0, -1, G);
    return centroid;
  }

  vector<int> partsize(const vector<int> G[]) {
    int c = centroid[0];
    vector<int> ret;
    int rest = N - 1;
    for (auto i : G[c]) {
      if (sz[i] < sz[c]) {
        ret.push_back(sz[i]);
        rest -= sz[i];
      }
    }
    if (rest > 0)
      ret.push_back(rest);
    return ret;
  }
};

const long long FACT_MAX = 5000;
long long famod[FACT_MAX + 1];
long long simod[FACT_MAX + 1];
long long fimod[FACT_MAX + 1];

const long long MOD = 1e9 + 7;

void create_fact_mod(int num) {
  famod[0] = 1;
  famod[1] = 1;
  for (int i = 2; i <= num; i++) {
    famod[i] = famod[i - 1] * i % MOD;
  }
}

void create_seq_inv_mod(int num) {
  simod[0] = 1;
  simod[1] = 1;
  for (int i = 2; i <= num; i++) {
    simod[i] = (MOD - MOD / i) * simod[MOD % i] % MOD;
  }
}

void create_fact_inv_mod(int num) {
  fimod[0] = 1;
  fimod[1] = 1;
  for (int i = 2; i <= num; i++) {
    fimod[i] = fimod[i - 1] * simod[i] % MOD;
  }
}

void create_mod_tables(int num) {
  create_fact_mod(num);
  create_seq_inv_mod(num);
  create_fact_inv_mod(num);
}

long long comb_mod(int n, int k) {
  return famod[n] * fimod[n - k] % MOD * fimod[k] % MOD;
}

long long perm_mod(int n, int k) { return famod[n] * fimod[n - k] % MOD; }

void add(long long &a, long long b) { a = (a + b + MOD) % MOD; }

int main() {
  long long i, j, k;
  int N;
  const int MAX = 5000;
  vector<int> edges[MAX];

  cin >> N;
  for (i = 0; i < N - 1; i++) {
    int x, y;
    cin >> x >> y;
    edges[x - 1].push_back(y - 1);
    edges[y - 1].push_back(x - 1);
  }

  Centroid ctr;
  auto centroid = ctr.calculate(N, edges);

  if (centroid.size() == 2) {
    long long ans = 1;
    for (i = 2; i <= N / 2; i++) {
      ans = ans * i * i % MOD;
    }
    cout << ans << endl;
    return 0;
  }

  auto partsize = ctr.partsize(edges);
  int K = partsize.size();
  long long dp[MAX][MAX + 1] = {0};
  dp[0][0] = 1;
  create_mod_tables(N);
  int sum = 0;

  for (i = 0; i < K; i++) {
    int ps = partsize[i];
    for (j = 0; j <= sum; j++) {
      for (k = 0; k <= ps; k++) {
        long long a = dp[i][j] * comb_mod(ps, k) % MOD * comb_mod(ps, k) % MOD *
                      famod[k] % MOD;
        add(dp[i + 1][j + k], a);
      }
    }
    sum += partsize[i];
  }

  long long ans = 0;
  for (i = 0; i <= N - 1; i++) {
    long long a = famod[N - i] * dp[K][i] * (i % 2 == 0 ? 1 : -1) % MOD;
    add(ans, a);
  }
  cout << ans << endl;
  return 0;
}