Problem p03039 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <iostream>

#define MOD (long)(1e9 + 7)
#define MAX 100000

using namespace std;

class modlong;
void computeAll(long n);
modlong modComb(long n, long k);

class modlong {
  long val;
  const long mod = MOD;

public:
  // 初期化 値を引数に与えなかった場合はval=0としておく
  modlong(long init = 0) {
    while (init < 0)
      init += mod; // 0以上であることを保証
    val = init % mod;
  }

  // longへのキャスト operator long()で定義すると modlong +
  // longとかができなくなる
  long tol() { return this->val; }

  // 代入
  void operator=(const modlong &r) { this->val = r.val; }
  void operator=(const long &r) {
    long rr = r;
    while (rr < 0)
      rr += mod; // 0以上であることを保証
    this->val = rr % mod;
  }

  // 比較
  bool operator<(const modlong &r) { return this->val < r.val; }
  bool operator>(const modlong &r) { return this->val > r.val; }
  bool operator==(const modlong &r) { return this->val == r.val; }
  bool operator!=(const modlong &r) { return !(*this == r); }
  bool operator<=(const modlong &r) { return !(*this > r); }
  bool operator>=(const modlong &r) { return !(*this < r); }

  // 足し算; 符号反転; 引き算
  modlong operator+(const modlong &r) {
    long aval = (this->val + r.val) % mod;
    modlong ans(aval);
    return ans;
  }
  modlong operator-() {
    long aval = (mod - this->val) % mod;
    modlong ans(aval);
    return ans;
  }
  modlong operator-(const modlong &r) {
    modlong rr = r;
    return *this + (-rr);
  }

  // かけ算; 逆元; わり算
  modlong operator*(const modlong &r) {
    long aval = (this->val * r.val) % mod;
    modlong ans(aval);
    return ans;
  }
  modlong inv() {
    if (*this == 1)
      return modlong(1);

    modlong p, q = *this, m(0), n(1), r, c;
    p.val = mod; // p=modとかくとp.val=mod%mod=0となってしまう
    while (q > 1) {
      r = p.val % q.val; // r.val=p.val / q.val
                         // とかくよりもこのほうが代入時に%modされるので安全
      c = m.val - n.val * (p.val / q.val);
      p = q, q = r, m = n, n = c;
    }
    return n;
  }
  modlong operator/(const modlong &r) {
    modlong rr = r;
    return *this * rr.inv();
  }

  // ++ -- 前付きと後ろ付き
  void operator++() { ++this->val; }
  void operator++(int a) { this->val++; }
  void operator--() { --this->val; }
  void operator--(int a) { this->val--; }

  // 四則演算&代入
  void operator+=(const modlong &r) { *this = *this + r; }
  void operator-=(const modlong &r) { *this = *this - r; }
  void operator*=(const modlong &r) { *this = *this * r; }
  void operator/=(const modlong &r) { *this = *this / r; }

  // べき乗
  modlong pow(long n) {
    if (n < 0)
      return inv().pow(-n); // 逆元の-n乗
    else if (n == 0)
      return modlong(1);

    modlong half = pow(n / 2);
    if (n % 2)
      return *this * half * half;
    else
      return half * half;
  }

  // コンビネーション modCombは少し下に書いてある
  modlong C(modlong k) { return modComb(this->val, k.val); }

  friend ostream &operator<<(ostream &os, const modlong &out);
  friend istream &operator>>(istream &is, modlong &out);
};

// cout、cerr、cin用の演算子たち
ostream &operator<<(ostream &os, const modlong &out) {
  os << out.val;
  return os;
}
istream &operator>>(istream &is, modlong &in) {
  long inl;
  is >> inl;
  in.val = inl % MOD;
  return is;
}

//////      階乗を全て求める -> 二項係数を求める

modlong invs[MAX], facts[MAX], finvs[MAX];
long listlen = 0; // invs, facts, finvsの配列長
void computeAll(long n) {
  long i;
  if (listlen == 0) {
    invs[1] = 1;
    facts[0] = 1;
    facts[1] = 1;
    finvs[0] = 1;
    finvs[1] = 1;
    i = 2;
  } else {
    i = listlen;
  }
  for (; i <= n; i++) {
    invs[i] = -invs[MOD % i] * modlong(MOD / i);
    facts[i] = facts[i - 1] * i;
    finvs[i] = finvs[i - 1] * invs[i];
  }
  listlen = n + 1; // 次呼び出すときはn+1以降から再開すれば良い
}
modlong modComb(long n, long k) {
  if (k < 0 || n < k)
    return 0;
  if (k == 0 || k == n)
    return 1;
  if (listlen <= n)
    computeAll(n); // 毎回足りない分だけ補う
  return facts[n] * finvs[k] * finvs[n - k];
}

int main() {
  long n, m, k;
  cin >> n >> m >> k;
  modlong sum = 0, comb = modComb(n * m - 2, k - 2);
  for (long d = 1; d < n; d++)
    sum += comb * d * (n - d) * m * m;
  for (long d = 1; d < m; d++)
    sum += comb * d * (m - d) * n * n;
  cout << sum << '\n';
  return 0;
}


Fixed submission:
#include <algorithm>
#include <iostream>

#define MOD (long)(1e9 + 7)
#define MAX 1000000

using namespace std;

class modlong;
void computeAll(long n);
modlong modComb(long n, long k);

class modlong {
  long val;
  const long mod = MOD;

public:
  // 初期化 値を引数に与えなかった場合はval=0としておく
  modlong(long init = 0) {
    while (init < 0)
      init += mod; // 0以上であることを保証
    val = init % mod;
  }

  // longへのキャスト operator long()で定義すると modlong +
  // longとかができなくなる
  long tol() { return this->val; }

  // 代入
  void operator=(const modlong &r) { this->val = r.val; }
  void operator=(const long &r) {
    long rr = r;
    while (rr < 0)
      rr += mod; // 0以上であることを保証
    this->val = rr % mod;
  }

  // 比較
  bool operator<(const modlong &r) { return this->val < r.val; }
  bool operator>(const modlong &r) { return this->val > r.val; }
  bool operator==(const modlong &r) { return this->val == r.val; }
  bool operator!=(const modlong &r) { return !(*this == r); }
  bool operator<=(const modlong &r) { return !(*this > r); }
  bool operator>=(const modlong &r) { return !(*this < r); }

  // 足し算; 符号反転; 引き算
  modlong operator+(const modlong &r) {
    long aval = (this->val + r.val) % mod;
    modlong ans(aval);
    return ans;
  }
  modlong operator-() {
    long aval = (mod - this->val) % mod;
    modlong ans(aval);
    return ans;
  }
  modlong operator-(const modlong &r) {
    modlong rr = r;
    return *this + (-rr);
  }

  // かけ算; 逆元; わり算
  modlong operator*(const modlong &r) {
    long aval = (this->val * r.val) % mod;
    modlong ans(aval);
    return ans;
  }
  modlong inv() {
    if (*this == 1)
      return modlong(1);

    modlong p, q = *this, m(0), n(1), r, c;
    p.val = mod; // p=modとかくとp.val=mod%mod=0となってしまう
    while (q > 1) {
      r = p.val % q.val; // r.val=p.val / q.val
                         // とかくよりもこのほうが代入時に%modされるので安全
      c = m.val - n.val * (p.val / q.val);
      p = q, q = r, m = n, n = c;
    }
    return n;
  }
  modlong operator/(const modlong &r) {
    modlong rr = r;
    return *this * rr.inv();
  }

  // ++ -- 前付きと後ろ付き
  void operator++() { ++this->val; }
  void operator++(int a) { this->val++; }
  void operator--() { --this->val; }
  void operator--(int a) { this->val--; }

  // 四則演算&代入
  void operator+=(const modlong &r) { *this = *this + r; }
  void operator-=(const modlong &r) { *this = *this - r; }
  void operator*=(const modlong &r) { *this = *this * r; }
  void operator/=(const modlong &r) { *this = *this / r; }

  // べき乗
  modlong pow(long n) {
    if (n < 0)
      return inv().pow(-n); // 逆元の-n乗
    else if (n == 0)
      return modlong(1);

    modlong half = pow(n / 2);
    if (n % 2)
      return *this * half * half;
    else
      return half * half;
  }

  // コンビネーション modCombは少し下に書いてある
  modlong C(modlong k) { return modComb(this->val, k.val); }

  friend ostream &operator<<(ostream &os, const modlong &out);
  friend istream &operator>>(istream &is, modlong &out);
};

// cout、cerr、cin用の演算子たち
ostream &operator<<(ostream &os, const modlong &out) {
  os << out.val;
  return os;
}
istream &operator>>(istream &is, modlong &in) {
  long inl;
  is >> inl;
  in.val = inl % MOD;
  return is;
}

//////      階乗を全て求める -> 二項係数を求める

modlong invs[MAX], facts[MAX], finvs[MAX];
long listlen = 0; // invs, facts, finvsの配列長
void computeAll(long n) {
  long i;
  if (listlen == 0) {
    invs[1] = 1;
    facts[0] = 1;
    facts[1] = 1;
    finvs[0] = 1;
    finvs[1] = 1;
    i = 2;
  } else {
    i = listlen;
  }
  for (; i <= n; i++) {
    invs[i] = -invs[MOD % i] * modlong(MOD / i);
    facts[i] = facts[i - 1] * i;
    finvs[i] = finvs[i - 1] * invs[i];
  }
  listlen = n + 1; // 次呼び出すときはn+1以降から再開すれば良い
}
modlong modComb(long n, long k) {
  if (k < 0 || n < k)
    return 0;
  if (k == 0 || k == n)
    return 1;
  if (listlen <= n)
    computeAll(n); // 毎回足りない分だけ補う
  return facts[n] * finvs[k] * finvs[n - k];
}

int main() {
  long n, m, k;
  cin >> n >> m >> k;
  modlong sum = 0, comb = modComb(n * m - 2, k - 2);
  for (long d = 1; d < n; d++)
    sum += comb * d * (n - d) * m * m;
  for (long d = 1; d < m; d++)
    sum += comb * d * (m - d) * n * n;
  cout << sum << '\n';
  return 0;
}