Problem p01452 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <numeric>
#include <queue>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// cin.sync_with_stdio(false);
// streambuf
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
using vi = vector<int>;
using vll = vector<ll>;
using vpii = vector<pii>;
template <class T, int s> using va = vector<array<T, s>>;
template <class T, class T2> using umap = unordered_map<T, T2>;
template <class T> using uset = unordered_set<T>;
template <class T, class S> void cmin(T &a, const S &&b) {
  if (a > b)
    a = b;
}
template <class T, class S> void cmax(T &a, const S &&b) {
  if (a < b)
    a = b;
}
#define ALL(a) a.begin(), a.end()
#define rep(i, a) for (int i = 0; i < a; i++)
#define rep1(i, a) for (int i = 1; i <= a; i++)
#define rrep(i, a) for (int i = a - 1; i >= 0; i--)
#define rrep1(i, a) for (int i = a; i; i--)
const ll mod = 1000000007;
#ifndef INT_MAX
const int INT_MAX = numeric_limits<signed>().max();
#endif
template <class T> using heap = priority_queue<T, vector<T>, greater<T>>;
template <class T> using pque = priority_queue<T, vector<T>, function<T(T, T)>>;
template <class T> inline void hash_combine(size_t &seed, const T &v) {
  hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std {

template <typename S, typename T> struct hash<pair<S, T>> {
  inline size_t operator()(const pair<S, T> &v) const {
    size_t seed = 0;
    hash_combine(seed, v.first);
    hash_combine(seed, v.second);
    return seed;
  }
};
// Recursive template code derived from Matthieu M.
template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
struct HashValueImpl {
  static void apply(size_t &seed, Tuple const &tuple) {
    HashValueImpl<Tuple, Index - 1>::apply(seed, tuple);
    hash_combine(seed, std::get<Index>(tuple));
  }
};

template <class Tuple> struct HashValueImpl<Tuple, 0> {
  static void apply(size_t &seed, Tuple const &tuple) {
    hash_combine(seed, std::get<0>(tuple));
  }
};

template <typename... TT> struct hash<std::tuple<TT...>> {
  size_t operator()(std::tuple<TT...> const &tt) const {
    size_t seed = 0;
    HashValueImpl<std::tuple<TT...>>::apply(seed, tt);
    return seed;
  }
};
} // namespace std
ll pow(ll base, ll i, ll mod) {
  ll a = 1;
  while (i) {
    if (i & 1) {
      a *= base;
      a %= mod;
    }
    base *= base;
    base %= mod;
    i /= 2;
  }
  return a;
}
class unionfind {
  vector<int> par, rank,
      size_; //????????§??????????????¢???????????????????????????rank???????????????size?????????
public:
  unionfind(int n) : par(n), rank(n), size_(n, 1) { iota(ALL(par), 0); }
  int find(int x) {
    if (par[x] == x)
      return x;
    return par[x] = find(par[x]);
  }
  void unite(int x, int y) {
    x = find(x), y = find(y);
    if (x == y)
      return;
    if (rank[x] < rank[y])
      swap(x, y);
    par[y] = x;
    size_[x] += size_[y];
    if (rank[x] == rank[y])
      rank[x]++;
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int size(int x) { return size_[find(x)]; }
};
ll gcd(ll a, ll b) {
  while (b) {
    ll c = a % b;
    a = b;
    b = c;
  }
  return a;
}
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }
int popcnt(unsigned long long a) {
  a = (a & 0x5555555555555555) + (a >> 1 & 0x5555555555555555);
  a = (a & 0x3333333333333333) + (a >> 2 & 0x3333333333333333);
  a = (a & 0x0f0f0f0f0f0f0f0f) + (a >> 4 & 0x0f0f0f0f0f0f0f0f);
  a = (a & 0x00ff00ff00ff00ff) + (a >> 8 & 0x00ff00ff00ff00ff);
  a = (a & 0x0000ffff0000ffff) + (a >> 16 & 0x0000ffff0000ffff);
  return (a & 0xffffffff) + (a >> 32);
}
template <class T, class Func = function<T(T, T)>> class segtree {
  vector<T> obj;
  int offset;
  Func updater;
  T e;
  int bufsize(int num) {
    int i = 1;
    for (; num > i; i <<= 1)
      ;
    offset = i - 1;
    return (i << 1) - 1;
  }
  T query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l)
      return e;
    if (a <= l && r <= b)
      return obj[k];
    else
      return updater(query(a, b, k * 2 + 1, l, (l + r) / 2),
                     query(a, b, k * 2 + 2, (l + r) / 2, r));
  }

public:
  T query(int a, int b) { //[a,b)
    return query(a, b, 0, 0, offset + 1);
  }
  void updateall(int l = 0, int r = -1) {
    if (r < 0)
      r = offset + 1;
    l += offset, r += offset;
    do {
      l = l - 1 >> 1, r = r - 1 >> 1;
      for (int i = l; i < r; i++)
        obj[i] = updater(obj[i * 2 + 1], obj[i * 2 + 2]);
    } while (l);
  }
  void update(int k, T &a) {
    k += offset;
    obj[k] = a;
    while (k) {
      k = k - 1 >> 1;
      obj[k] = updater(obj[k * 2 + 1], obj[k * 2 + 2]);
    }
  }
  segtree(int n, T e, const Func &updater_ = Func())
      : obj(bufsize(n), e), e(e), updater(updater_) {}
  segtree(vector<T> &vec, T e, const Func &updater = Func())
      : obj(bufsize(vec.size()), e), e(e), updater(updater) {
    copy(vec.begin(), vec.end(), obj.begin() + offset);
    updateall();
  }
  typename vector<T>::reference operator[](int n) { return obj[n + offset]; }
};
template <class T> class matrix {
  vector<vector<T>> obj;
  pair<int, int> s;

public:
  matrix(pair<int, int> size, T e = 0) : matrix(size.first, size.second, e) {}
  matrix(int n, int m = -1, T e = 0)
      : obj(n, vector<T>(m == -1 ? n : m, e)), s(n, m == -1 ? n : m) {}
  static matrix e(int n) {
    matrix a = (n);
    for (int i = 0; i < n; i++)
      a[i][i] = 1;
    return a;
  }
  matrix &operator+=(const matrix &p) {
    if (s != p.s)
      throw runtime_error("matrix error");
    for (int i = 0; i < s.first; i++)
      for (int j = 0; j < s.second; j++)
        obj[i][j] += p.obj[i][j];
    return *this;
  }
  matrix operator+(const matrix &p) {
    matrix res(*this);
    return res += p;
  }
  matrix &operator-=(const matrix &p) {
    if (s != p.s)
      throw runtime_error("matrix error");
    for (int i = 0; i < s.first; i++)
      for (int j = 0; j < s.second; j++)
        obj[i][j] -= p.obj[i][j];
    return *this;
  }
  matrix operator-(const matrix &p) {
    matrix res(*this);
    return res -= p;
  }
  matrix &operator*=(T p) {
    for (auto &a : obj)
      for (auto &b : a)
        b *= p;
    return *this;
  }
  matrix operator*(T p) {
    matrix res(*this);
    return res *= p;
  }
  matrix operator*(const matrix &p) {
    if (s.second != p.s.first)
      throw runtime_error("matrix error");
    matrix ret(s.first, p.s.second);
    for (int i = 0; i < s.first; i++)
      for (int j = 0; j < s.second; j++)
        for (int k = 0; k < p.s.second; k++)
          ret[i][k] += obj[i][j] * p.obj[j][k];
    return ret;
  }
  matrix &operator*=(const matrix &p) { return *this = *this * p; }
  pair<int, int> size() const { return s; }
  matrix &mod(T m) {
    for (auto &a : obj)
      for (auto &b : a)
        b %= m;
    return *this;
  }
  typename vector<vector<T>>::reference operator[](int t) { return obj[t]; }
};
template <class T> inline matrix<T> pow(matrix<T> &base, unsigned exp) {
  auto base_(base);
  if (base_.size().first != base_.size().second)
    throw runtime_error("matrix error");
  matrix<T> res = matrix<T>::e(base_.size().first);
  for (;;) {
    if (exp & 1)
      res *= base_;
    if (!(exp /= 2))
      break;
    base_ *= base_;
  }
  return res;
}
template <class T> inline matrix<T> modpow(matrix<T> &base, unsigned exp, T m) {
  auto base_(base);
  if (base.size().first != base_.size().second)
    throw runtime_error("matrix error");
  matrix<T> res = matrix<T>::e(base_.size().first);
  for (;;) {
    if (exp & 1)
      (res *= base_).mod(m);
    if (!(exp /= 2))
      break;
    (base_ *= base_).mod(m);
  }
  return res;
}
template <class T> int id(vector<T> &a, T b) {
  return lower_bound(ALL(a), b) - a.begin();
}
class Flow {
  int V;
  struct edge {
    int to, cap, rev, cost;
  };
  vector<vector<edge>> G;
  vector<int> level, iter, h, dist, prevv, preve;
  Flow(int size) : G(size + 1), V(size + 1) {}
  void add_edge(int from, int to, int cap, int cost = 0) {
    G[from].push_back(edge{to, cap, (int)G[to].size(), cost});
    G[to].push_back(edge{from, 0, (int)G[from].size() - 1, -cost});
  }
  void bfs(int s) {
    fill(level.begin(), level.end(), -1);
    queue<int> que;
    level[s] = 0;
    que.push(s);
    while (!que.empty()) {
      int v = que.front();
      que.pop();
      for (int i = 0; i < G[v].size(); i++) {
        edge &e = G[v][i];
        if (e.cap > 0 && level[e.to] < 0) {
          level[e.to] = level[v] + 1;
          que.push(e.to);
        }
      }
    }
  }
  int dfs(int v, int t, int f) {
    if (v == t)
      return f;
    for (int &i = iter[v]; i < G[v].size(); i++) {
      edge &e = G[v][i];
      if (e.cap > 0 && level[v] < level[e.to]) {
        int d = dfs(e.to, t, min(f, e.cap));
        if (d > 0) {
          e.cap -= d;
          G[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }
  int max_flow(int s, int t) {
    level.resize(V);
    iter.resize(V);
    int flow = 0;
    for (;;) {
      bfs(s);
      if (level[t] < 0)
        return flow;
      fill(iter.begin(), iter.end(), 0);
      int f;
      while ((f = dfs(s, t, numeric_limits<int>::max())) > 0) {
        flow += f;
      }
    }
  }
  typedef pair<int, int> P;
  int min_cost_flow(int s, int t, int f) {
    int res = 0;
    h.resize(V);
    dist.resize(V);
    prevv.resize(V);
    preve.resize(V);
    fill(h.begin(), h.end(), 0);
    while (f > 0) {
      priority_queue<P, vector<P>, greater<P>> que;
      fill(dist.begin(), dist.end(), numeric_limits<int>::max());
      dist[s] = 0;
      que.push({0, s});
      while (!que.empty()) {
        P p = que.top();
        que.pop();
        int v = p.second;
        if (dist[v] < p.first)
          continue;
        for (int i = 0; i < G[v].size(); i++) {
          edge &e = G[v][i];
          if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
            dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
            prevv[e.to] = v;
            preve[e.to] = i;
            que.push({dist[e.to], e.to});
          }
        }
      }
      if (dist[t] == numeric_limits<int>::max()) {
        return -1;
      }
      for (int v = 0; v < V; v++)
        h[v] += dist[v];

      int d = f;
      for (int v = t; v != s; v = prevv[v]) {
        d = min(d, G[prevv[v]][preve[v]].cap);
      }
      f -= d;
      res += d * h[t];
      for (int v = t; v != s; v = prevv[v]) {
        edge &e = G[prevv[v]][preve[v]];
        e.cap -= d;
        G[v][e.rev].cap += d;
      }
    }
    return res;
  }
};
const ld eps = 1e-11, pi = acos(-1.0);
typedef complex<ld> P;
typedef vector<P> VP;
ld dot(P a, P b) { return real(conj(a) * b); }
ld cross(P a, P b) { return imag(conj(a) * b); }

namespace std {
bool operator<(const P &a, const P &b) {
  return abs(a.real() - b.real()) < eps ? a.imag() < b.imag()
                                        : a.real() < b.real();
}
} // namespace std

struct L {
  P a, b;
}; // line->l,segment->s
struct C {
  P p;
  ld r;
};

int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > eps)
    return 1; // counter clockwise
  if (cross(b, c) < -eps)
    return -1; // clockwise
  if (dot(b, c) < 0)
    return 2; // c--a--b on line
  if (norm(b) < norm(c))
    return -2; // a--b--c on line
  return 0;    // a--c--b on line
}

bool isis_ll(L l, L m) { // is intersect
  return abs(cross(l.b - l.a, m.b - m.a)) > eps;
}

bool isis_ls(L l, L s) {
  ld a = cross(l.b - l.a, s.a - l.a);
  ld b = cross(l.b - l.a, s.b - l.a);
  return (a * b < eps);
}

bool isis_lp(L l, P p) { return abs(cross(l.b - p, l.a - p)) < eps; }

bool isis_ss(L s, L t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

P is_ll(L s, L t) { // intersect
  P sv = s.b - s.a, tv = t.b - t.a;
  return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

bool isis_sp(L s, P p) {
  return abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps;
}

P proj(L l, P p) {
  ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + t * (l.a - l.b);
}

ld dist_lp(L l, P p) { return abs(p - proj(l, p)); }

ld dist_ll(L l, L m) { return isis_ll(l, m) ? 0 : dist_lp(l, m.a); }

ld dist_ls(L l, L s) {
  if (isis_ls(l, s))
    return 0;
  return min(dist_lp(l, s.a), dist_lp(l, s.b));
}

ld dist_sp(L s, P p) {
  P r = proj(s, p);
  if (isis_sp(s, r))
    return abs(r - p);
  return min(abs(s.a - p), abs(s.b - p));
}

ld dist_ss(L s, L t) {
  if (isis_ss(s, t))
    return 0;
  ld a = min(dist_sp(s, t.a), dist_sp(t, s.a));
  ld b = min(dist_sp(s, t.b), dist_sp(t, s.b));
  return min(a, b);
}

VP is_cc(C c1, C c2) {
  VP res;
  ld d = abs(c1.p - c2.p);
  ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
  ld dfr = c1.r * c1.r - rc * rc;
  if (abs(dfr) < eps)
    dfr = 0.0;
  else if (dfr < 0.0)
    return res; // no intersection
  ld rs = sqrt(dfr);
  P diff = (c2.p - c1.p) / d;
  res.push_back(c1.p + diff * P(rc, rs));
  if (dfr != 0.0)
    res.push_back(c1.p + diff * P(rc, -rs));
  return res;
}

bool isis_vc(vector<C> vc) {
  VP crs;
  int n = vc.size();
  rep(i, n) rep(j, i) for (P p : is_cc(vc[i], vc[j])) crs.push_back(p);
  rep(i, n) crs.push_back(vc[i].p);
  for (P p : crs) {
    bool valid = true;
    rep(i, n) if (abs(p - vc[i].p) > vc[i].r + eps) valid = false;
    if (valid)
      return true;
  }
  return false;
}

VP is_lc(C c, L l) {
  VP res;
  ld d = dist_lp(l, c.p);
  if (d < c.r + eps) {
    ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); // safety;
    P nor = (l.a - l.b) / abs(l.a - l.b);
    res.push_back(proj(l, c.p) + len * nor);
    res.push_back(proj(l, c.p) - len * nor);
  }
  return res;
}

VP is_sc(C c, L l) {
  VP v = is_lc(c, l), res;
  for (P p : v)
    if (isis_sp(l, p))
      res.push_back(p);
  return res;
}

vector<L> tangent_cp(C c, P p) { //????????\\????
  vector<L> ret;
  P v = c.p - p;
  ld d = abs(v);
  ld l = sqrt(norm(v) - c.r * c.r);
  if (isnan(l)) {
    return ret;
  }
  P v1 = v * P(l / d, c.r / d);
  P v2 = v * P(l / d, -c.r / d);
  ret.push_back(L{p, p + v1});
  if (l < eps)
    return ret;
  ret.push_back(L{p, p + v2});
  return ret;
}

vector<L> tangent_cc(C c1, C c2) {
  vector<L> ret;
  if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
    P center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
    ret = tangent_cp(c1, center);
  }
  if (abs(c1.r - c2.r) > eps) {
    P out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
    vector<L> nret = tangent_cp(c1, out);
    ret.insert(ret.end(), ALL(nret));
  } else {
    P v = c2.p - c1.p;
    v /= abs(v);
    P q1 = c1.p + v * P(0, 1) * c1.r;
    P q2 = c1.p + v * P(0, -1) * c1.r;
    ret.push_back(L{q1, q1 + v});
    ret.push_back(L{q2, q2 + v});
  }
  return ret;
}

ld area(const VP &p) { //??¢?????
  ld res = 0;
  int n = p.size();
  rep(j, n) res += cross(p[j], p[(j + 1) % n]);
  return res / 2;
}

bool is_polygon(L l, VP &g) {
  int n = g.size();
  for (int i = 0; i < n; i++) {
    P a = g[i];
    P b = g[(i + 1) % n];
    if (isis_ss(l, L{a, b}))
      return true;
  }
  return false;
}

int is_in_Polygon(const VP &g, P p) {
  bool in = false;
  int n = g.size();
  for (int i = 0; i < n; i++) {
    P a = g[i] - p, b = g[(i + 1) % n] - p;
    if (imag(a) > imag(b))
      swap(a, b);
    if (imag(a) <= 0 && 0 < imag(b))
      if (cross(a, b) < 0)
        in = !in;
    if (abs(cross(a, b)) < eps && dot(a, b) < eps)
      return 0; // on
  }
  if (in)
    return 1; // in
  return -1;  // out
}

VP ConvexHull(VP ps) {
  int n = ps.size();
  int k = 0;
  sort(ps.begin(), ps.end());
  VP ch(2 * n);
  for (int i = 0; i < n; ch[k++] = ps[i++])
    while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--])
    while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  ch.resize(k - 1);
  return ch;
}

VP ConvexCut(const VP &ps, L l) {
  VP Q;
  for (int i = 0; i < (int)ps.size(); i++) {
    P A = ps[i], B = ps[(i + 1) % ps.size()];
    if (ccw(l.a, l.b, A) != -1)
      Q.push_back(A);
    if (ccw(l.a, l.b, A) * ccw(l.a, l.b, B) < 0)
      Q.push_back(is_ll(L{A, B}, l));
  }
  return Q;
}
double dist2(P a) { return real(a) * real(a) + imag(a) * imag(a); }
// Suffix Array	?????????O(|S|log^2|S|), ????´¢O(|T|log|S|),
// ?????????????§????O(|S|)
class StringSearch {
  const int n;
  string S;

public:
  vector<int> sa, rank;
  StringSearch(const string &S_) : n(S_.size()), S(S_), sa(n + 1), rank(n + 1) {
    for (int i = 0; i <= n; i++) {
      sa[i] = i;
      rank[i] = i < n ? S[i] : -1;
    }
    vector<int> tmp(n + 1);
    for (int k = 1; k <= n; k *= 2) {
      auto Compare_SA = [=](int i, int j) {
        if (this->rank[i] != this->rank[j])
          return this->rank[i] < this->rank[j];

        int ri = i + k <= n ? this->rank[i + k] : -1;
        int rj = j + k <= n ? this->rank[j + k] : -1;
        return ri < rj;
      };
      sort(sa.begin(), sa.end(), Compare_SA);
      tmp[sa[0]] = 0;
      for (int i = 1; i <= n; i++) {
        tmp[sa[i]] = tmp[sa[i - 1]] + (Compare_SA(sa[i - 1], sa[i]) ? 1 : 0);
      }
      for (int i = 0; i <= n; i++) {
        this->rank[i] = tmp[i];
      }
    }
  }
  bool Contain(const string &T) {
    int a = 0, b = n;
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (S.compare(sa[c], T.length(), T) < 0)
        a = c;
      else
        b = c;
    }
    return S.compare(sa[b], T.length(), T) == 0;
  }
  vector<int> LCPArray() {
    for (int i = 0; i <= n; i++)
      rank[sa[i]] = i;
    int h = 0;
    vector<int> lcp(n + 1);
    for (int i = 0; i < n; i++) {
      int j = sa[rank[i] - 1];
      if (h > 0)
        h--;
      for (; j + h < n && i + h < n; h++) {
        if (S[j + h] != S[i + h])
          break;
      }
      lcp[rank[i] - 1] = h;
    }
    return lcp;
  }
};
int memo[(int)22e4 + 1];
int main() {
  ll a = 1;
  memo[0] = 1;
  rep1(i, 22e4) memo[i] = a = a * i % mod;
  int n, m, k;
  cin >> n >> m >> k;
  ll ans = 0;
  rep(i, k + 1) {
    ans += (ll)memo[n + m + k * 2] * (n + 1) % mod * (m + 1) % mod *
           pow((ll)memo[i] * memo[n + 1 + i] % mod * memo[k - i] % mod *
                   memo[m + 1 + k - i] % mod,
               mod - 2, mod);
    ans %= mod;
  }
  cout << ans << endl;
}

Error: 0

Fixed submission:

#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <complex>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <numeric>
#include <queue>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// cin.sync_with_stdio(false);
// streambuf
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
using vi = vector<int>;
using vll = vector<ll>;
using vpii = vector<pii>;
template <class T, int s> using va = vector<array<T, s>>;
template <class T, class T2> using umap = unordered_map<T, T2>;
template <class T> using uset = unordered_set<T>;
template <class T, class S> void cmin(T &a, const S &&b) {
  if (a > b)
    a = b;
}
template <class T, class S> void cmax(T &a, const S &&b) {
  if (a < b)
    a = b;
}
#define ALL(a) a.begin(), a.end()
#define rep(i, a) for (int i = 0; i < a; i++)
#define rep1(i, a) for (int i = 1; i <= a; i++)
#define rrep(i, a) for (int i = a - 1; i >= 0; i--)
#define rrep1(i, a) for (int i = a; i; i--)
const ll mod = 1000000007;
#ifndef INT_MAX
const int INT_MAX = numeric_limits<signed>().max();
#endif
template <class T> using heap = priority_queue<T, vector<T>, greater<T>>;
template <class T> using pque = priority_queue<T, vector<T>, function<T(T, T)>>;
template <class T> inline void hash_combine(size_t &seed, const T &v) {
  hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
namespace std {

template <typename S, typename T> struct hash<pair<S, T>> {
  inline size_t operator()(const pair<S, T> &v) const {
    size_t seed = 0;
    hash_combine(seed, v.first);
    hash_combine(seed, v.second);
    return seed;
  }
};
// Recursive template code derived from Matthieu M.
template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
struct HashValueImpl {
  static void apply(size_t &seed, Tuple const &tuple) {
    HashValueImpl<Tuple, Index - 1>::apply(seed, tuple);
    hash_combine(seed, std::get<Index>(tuple));
  }
};

template <class Tuple> struct HashValueImpl<Tuple, 0> {
  static void apply(size_t &seed, Tuple const &tuple) {
    hash_combine(seed, std::get<0>(tuple));
  }
};

template <typename... TT> struct hash<std::tuple<TT...>> {
  size_t operator()(std::tuple<TT...> const &tt) const {
    size_t seed = 0;
    HashValueImpl<std::tuple<TT...>>::apply(seed, tt);
    return seed;
  }
};
} // namespace std
ll pow(ll base, ll i, ll mod) {
  ll a = 1;
  while (i) {
    if (i & 1) {
      a *= base;
      a %= mod;
    }
    base *= base;
    base %= mod;
    i /= 2;
  }
  return a;
}
class unionfind {
  vector<int> par, rank,
      size_; //????????§??????????????¢???????????????????????????rank???????????????size?????????
public:
  unionfind(int n) : par(n), rank(n), size_(n, 1) { iota(ALL(par), 0); }
  int find(int x) {
    if (par[x] == x)
      return x;
    return par[x] = find(par[x]);
  }
  void unite(int x, int y) {
    x = find(x), y = find(y);
    if (x == y)
      return;
    if (rank[x] < rank[y])
      swap(x, y);
    par[y] = x;
    size_[x] += size_[y];
    if (rank[x] == rank[y])
      rank[x]++;
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int size(int x) { return size_[find(x)]; }
};
ll gcd(ll a, ll b) {
  while (b) {
    ll c = a % b;
    a = b;
    b = c;
  }
  return a;
}
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }
int popcnt(unsigned long long a) {
  a = (a & 0x5555555555555555) + (a >> 1 & 0x5555555555555555);
  a = (a & 0x3333333333333333) + (a >> 2 & 0x3333333333333333);
  a = (a & 0x0f0f0f0f0f0f0f0f) + (a >> 4 & 0x0f0f0f0f0f0f0f0f);
  a = (a & 0x00ff00ff00ff00ff) + (a >> 8 & 0x00ff00ff00ff00ff);
  a = (a & 0x0000ffff0000ffff) + (a >> 16 & 0x0000ffff0000ffff);
  return (a & 0xffffffff) + (a >> 32);
}
template <class T, class Func = function<T(T, T)>> class segtree {
  vector<T> obj;
  int offset;
  Func updater;
  T e;
  int bufsize(int num) {
    int i = 1;
    for (; num > i; i <<= 1)
      ;
    offset = i - 1;
    return (i << 1) - 1;
  }
  T query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l)
      return e;
    if (a <= l && r <= b)
      return obj[k];
    else
      return updater(query(a, b, k * 2 + 1, l, (l + r) / 2),
                     query(a, b, k * 2 + 2, (l + r) / 2, r));
  }

public:
  T query(int a, int b) { //[a,b)
    return query(a, b, 0, 0, offset + 1);
  }
  void updateall(int l = 0, int r = -1) {
    if (r < 0)
      r = offset + 1;
    l += offset, r += offset;
    do {
      l = l - 1 >> 1, r = r - 1 >> 1;
      for (int i = l; i < r; i++)
        obj[i] = updater(obj[i * 2 + 1], obj[i * 2 + 2]);
    } while (l);
  }
  void update(int k, T &a) {
    k += offset;
    obj[k] = a;
    while (k) {
      k = k - 1 >> 1;
      obj[k] = updater(obj[k * 2 + 1], obj[k * 2 + 2]);
    }
  }
  segtree(int n, T e, const Func &updater_ = Func())
      : obj(bufsize(n), e), e(e), updater(updater_) {}
  segtree(vector<T> &vec, T e, const Func &updater = Func())
      : obj(bufsize(vec.size()), e), e(e), updater(updater) {
    copy(vec.begin(), vec.end(), obj.begin() + offset);
    updateall();
  }
  typename vector<T>::reference operator[](int n) { return obj[n + offset]; }
};
template <class T> class matrix {
  vector<vector<T>> obj;
  pair<int, int> s;

public:
  matrix(pair<int, int> size, T e = 0) : matrix(size.first, size.second, e) {}
  matrix(int n, int m = -1, T e = 0)
      : obj(n, vector<T>(m == -1 ? n : m, e)), s(n, m == -1 ? n : m) {}
  static matrix e(int n) {
    matrix a = (n);
    for (int i = 0; i < n; i++)
      a[i][i] = 1;
    return a;
  }
  matrix &operator+=(const matrix &p) {
    if (s != p.s)
      throw runtime_error("matrix error");
    for (int i = 0; i < s.first; i++)
      for (int j = 0; j < s.second; j++)
        obj[i][j] += p.obj[i][j];
    return *this;
  }
  matrix operator+(const matrix &p) {
    matrix res(*this);
    return res += p;
  }
  matrix &operator-=(const matrix &p) {
    if (s != p.s)
      throw runtime_error("matrix error");
    for (int i = 0; i < s.first; i++)
      for (int j = 0; j < s.second; j++)
        obj[i][j] -= p.obj[i][j];
    return *this;
  }
  matrix operator-(const matrix &p) {
    matrix res(*this);
    return res -= p;
  }
  matrix &operator*=(T p) {
    for (auto &a : obj)
      for (auto &b : a)
        b *= p;
    return *this;
  }
  matrix operator*(T p) {
    matrix res(*this);
    return res *= p;
  }
  matrix operator*(const matrix &p) {
    if (s.second != p.s.first)
      throw runtime_error("matrix error");
    matrix ret(s.first, p.s.second);
    for (int i = 0; i < s.first; i++)
      for (int j = 0; j < s.second; j++)
        for (int k = 0; k < p.s.second; k++)
          ret[i][k] += obj[i][j] * p.obj[j][k];
    return ret;
  }
  matrix &operator*=(const matrix &p) { return *this = *this * p; }
  pair<int, int> size() const { return s; }
  matrix &mod(T m) {
    for (auto &a : obj)
      for (auto &b : a)
        b %= m;
    return *this;
  }
  typename vector<vector<T>>::reference operator[](int t) { return obj[t]; }
};
template <class T> inline matrix<T> pow(matrix<T> &base, unsigned exp) {
  auto base_(base);
  if (base_.size().first != base_.size().second)
    throw runtime_error("matrix error");
  matrix<T> res = matrix<T>::e(base_.size().first);
  for (;;) {
    if (exp & 1)
      res *= base_;
    if (!(exp /= 2))
      break;
    base_ *= base_;
  }
  return res;
}
template <class T> inline matrix<T> modpow(matrix<T> &base, unsigned exp, T m) {
  auto base_(base);
  if (base.size().first != base_.size().second)
    throw runtime_error("matrix error");
  matrix<T> res = matrix<T>::e(base_.size().first);
  for (;;) {
    if (exp & 1)
      (res *= base_).mod(m);
    if (!(exp /= 2))
      break;
    (base_ *= base_).mod(m);
  }
  return res;
}
template <class T> int id(vector<T> &a, T b) {
  return lower_bound(ALL(a), b) - a.begin();
}
class Flow {
  int V;
  struct edge {
    int to, cap, rev, cost;
  };
  vector<vector<edge>> G;
  vector<int> level, iter, h, dist, prevv, preve;
  Flow(int size) : G(size + 1), V(size + 1) {}
  void add_edge(int from, int to, int cap, int cost = 0) {
    G[from].push_back(edge{to, cap, (int)G[to].size(), cost});
    G[to].push_back(edge{from, 0, (int)G[from].size() - 1, -cost});
  }
  void bfs(int s) {
    fill(level.begin(), level.end(), -1);
    queue<int> que;
    level[s] = 0;
    que.push(s);
    while (!que.empty()) {
      int v = que.front();
      que.pop();
      for (int i = 0; i < G[v].size(); i++) {
        edge &e = G[v][i];
        if (e.cap > 0 && level[e.to] < 0) {
          level[e.to] = level[v] + 1;
          que.push(e.to);
        }
      }
    }
  }
  int dfs(int v, int t, int f) {
    if (v == t)
      return f;
    for (int &i = iter[v]; i < G[v].size(); i++) {
      edge &e = G[v][i];
      if (e.cap > 0 && level[v] < level[e.to]) {
        int d = dfs(e.to, t, min(f, e.cap));
        if (d > 0) {
          e.cap -= d;
          G[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }
  int max_flow(int s, int t) {
    level.resize(V);
    iter.resize(V);
    int flow = 0;
    for (;;) {
      bfs(s);
      if (level[t] < 0)
        return flow;
      fill(iter.begin(), iter.end(), 0);
      int f;
      while ((f = dfs(s, t, numeric_limits<int>::max())) > 0) {
        flow += f;
      }
    }
  }
  typedef pair<int, int> P;
  int min_cost_flow(int s, int t, int f) {
    int res = 0;
    h.resize(V);
    dist.resize(V);
    prevv.resize(V);
    preve.resize(V);
    fill(h.begin(), h.end(), 0);
    while (f > 0) {
      priority_queue<P, vector<P>, greater<P>> que;
      fill(dist.begin(), dist.end(), numeric_limits<int>::max());
      dist[s] = 0;
      que.push({0, s});
      while (!que.empty()) {
        P p = que.top();
        que.pop();
        int v = p.second;
        if (dist[v] < p.first)
          continue;
        for (int i = 0; i < G[v].size(); i++) {
          edge &e = G[v][i];
          if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
            dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
            prevv[e.to] = v;
            preve[e.to] = i;
            que.push({dist[e.to], e.to});
          }
        }
      }
      if (dist[t] == numeric_limits<int>::max()) {
        return -1;
      }
      for (int v = 0; v < V; v++)
        h[v] += dist[v];

      int d = f;
      for (int v = t; v != s; v = prevv[v]) {
        d = min(d, G[prevv[v]][preve[v]].cap);
      }
      f -= d;
      res += d * h[t];
      for (int v = t; v != s; v = prevv[v]) {
        edge &e = G[prevv[v]][preve[v]];
        e.cap -= d;
        G[v][e.rev].cap += d;
      }
    }
    return res;
  }
};
const ld eps = 1e-11, pi = acos(-1.0);
typedef complex<ld> P;
typedef vector<P> VP;
ld dot(P a, P b) { return real(conj(a) * b); }
ld cross(P a, P b) { return imag(conj(a) * b); }

namespace std {
bool operator<(const P &a, const P &b) {
  return abs(a.real() - b.real()) < eps ? a.imag() < b.imag()
                                        : a.real() < b.real();
}
} // namespace std

struct L {
  P a, b;
}; // line->l,segment->s
struct C {
  P p;
  ld r;
};

int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > eps)
    return 1; // counter clockwise
  if (cross(b, c) < -eps)
    return -1; // clockwise
  if (dot(b, c) < 0)
    return 2; // c--a--b on line
  if (norm(b) < norm(c))
    return -2; // a--b--c on line
  return 0;    // a--c--b on line
}

bool isis_ll(L l, L m) { // is intersect
  return abs(cross(l.b - l.a, m.b - m.a)) > eps;
}

bool isis_ls(L l, L s) {
  ld a = cross(l.b - l.a, s.a - l.a);
  ld b = cross(l.b - l.a, s.b - l.a);
  return (a * b < eps);
}

bool isis_lp(L l, P p) { return abs(cross(l.b - p, l.a - p)) < eps; }

bool isis_ss(L s, L t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
         ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

P is_ll(L s, L t) { // intersect
  P sv = s.b - s.a, tv = t.b - t.a;
  return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

bool isis_sp(L s, P p) {
  return abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps;
}

P proj(L l, P p) {
  ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + t * (l.a - l.b);
}

ld dist_lp(L l, P p) { return abs(p - proj(l, p)); }

ld dist_ll(L l, L m) { return isis_ll(l, m) ? 0 : dist_lp(l, m.a); }

ld dist_ls(L l, L s) {
  if (isis_ls(l, s))
    return 0;
  return min(dist_lp(l, s.a), dist_lp(l, s.b));
}

ld dist_sp(L s, P p) {
  P r = proj(s, p);
  if (isis_sp(s, r))
    return abs(r - p);
  return min(abs(s.a - p), abs(s.b - p));
}

ld dist_ss(L s, L t) {
  if (isis_ss(s, t))
    return 0;
  ld a = min(dist_sp(s, t.a), dist_sp(t, s.a));
  ld b = min(dist_sp(s, t.b), dist_sp(t, s.b));
  return min(a, b);
}

VP is_cc(C c1, C c2) {
  VP res;
  ld d = abs(c1.p - c2.p);
  ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
  ld dfr = c1.r * c1.r - rc * rc;
  if (abs(dfr) < eps)
    dfr = 0.0;
  else if (dfr < 0.0)
    return res; // no intersection
  ld rs = sqrt(dfr);
  P diff = (c2.p - c1.p) / d;
  res.push_back(c1.p + diff * P(rc, rs));
  if (dfr != 0.0)
    res.push_back(c1.p + diff * P(rc, -rs));
  return res;
}

bool isis_vc(vector<C> vc) {
  VP crs;
  int n = vc.size();
  rep(i, n) rep(j, i) for (P p : is_cc(vc[i], vc[j])) crs.push_back(p);
  rep(i, n) crs.push_back(vc[i].p);
  for (P p : crs) {
    bool valid = true;
    rep(i, n) if (abs(p - vc[i].p) > vc[i].r + eps) valid = false;
    if (valid)
      return true;
  }
  return false;
}

VP is_lc(C c, L l) {
  VP res;
  ld d = dist_lp(l, c.p);
  if (d < c.r + eps) {
    ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); // safety;
    P nor = (l.a - l.b) / abs(l.a - l.b);
    res.push_back(proj(l, c.p) + len * nor);
    res.push_back(proj(l, c.p) - len * nor);
  }
  return res;
}

VP is_sc(C c, L l) {
  VP v = is_lc(c, l), res;
  for (P p : v)
    if (isis_sp(l, p))
      res.push_back(p);
  return res;
}

vector<L> tangent_cp(C c, P p) { //????????\\????
  vector<L> ret;
  P v = c.p - p;
  ld d = abs(v);
  ld l = sqrt(norm(v) - c.r * c.r);
  if (isnan(l)) {
    return ret;
  }
  P v1 = v * P(l / d, c.r / d);
  P v2 = v * P(l / d, -c.r / d);
  ret.push_back(L{p, p + v1});
  if (l < eps)
    return ret;
  ret.push_back(L{p, p + v2});
  return ret;
}

vector<L> tangent_cc(C c1, C c2) {
  vector<L> ret;
  if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
    P center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
    ret = tangent_cp(c1, center);
  }
  if (abs(c1.r - c2.r) > eps) {
    P out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
    vector<L> nret = tangent_cp(c1, out);
    ret.insert(ret.end(), ALL(nret));
  } else {
    P v = c2.p - c1.p;
    v /= abs(v);
    P q1 = c1.p + v * P(0, 1) * c1.r;
    P q2 = c1.p + v * P(0, -1) * c1.r;
    ret.push_back(L{q1, q1 + v});
    ret.push_back(L{q2, q2 + v});
  }
  return ret;
}

ld area(const VP &p) { //??¢?????
  ld res = 0;
  int n = p.size();
  rep(j, n) res += cross(p[j], p[(j + 1) % n]);
  return res / 2;
}

bool is_polygon(L l, VP &g) {
  int n = g.size();
  for (int i = 0; i < n; i++) {
    P a = g[i];
    P b = g[(i + 1) % n];
    if (isis_ss(l, L{a, b}))
      return true;
  }
  return false;
}

int is_in_Polygon(const VP &g, P p) {
  bool in = false;
  int n = g.size();
  for (int i = 0; i < n; i++) {
    P a = g[i] - p, b = g[(i + 1) % n] - p;
    if (imag(a) > imag(b))
      swap(a, b);
    if (imag(a) <= 0 && 0 < imag(b))
      if (cross(a, b) < 0)
        in = !in;
    if (abs(cross(a, b)) < eps && dot(a, b) < eps)
      return 0; // on
  }
  if (in)
    return 1; // in
  return -1;  // out
}

VP ConvexHull(VP ps) {
  int n = ps.size();
  int k = 0;
  sort(ps.begin(), ps.end());
  VP ch(2 * n);
  for (int i = 0; i < n; ch[k++] = ps[i++])
    while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--])
    while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  ch.resize(k - 1);
  return ch;
}

VP ConvexCut(const VP &ps, L l) {
  VP Q;
  for (int i = 0; i < (int)ps.size(); i++) {
    P A = ps[i], B = ps[(i + 1) % ps.size()];
    if (ccw(l.a, l.b, A) != -1)
      Q.push_back(A);
    if (ccw(l.a, l.b, A) * ccw(l.a, l.b, B) < 0)
      Q.push_back(is_ll(L{A, B}, l));
  }
  return Q;
}
double dist2(P a) { return real(a) * real(a) + imag(a) * imag(a); }
// Suffix Array	?????????O(|S|log^2|S|), ????´¢O(|T|log|S|),
// ?????????????§????O(|S|)
class StringSearch {
  const int n;
  string S;

public:
  vector<int> sa, rank;
  StringSearch(const string &S_) : n(S_.size()), S(S_), sa(n + 1), rank(n + 1) {
    for (int i = 0; i <= n; i++) {
      sa[i] = i;
      rank[i] = i < n ? S[i] : -1;
    }
    vector<int> tmp(n + 1);
    for (int k = 1; k <= n; k *= 2) {
      auto Compare_SA = [=](int i, int j) {
        if (this->rank[i] != this->rank[j])
          return this->rank[i] < this->rank[j];

        int ri = i + k <= n ? this->rank[i + k] : -1;
        int rj = j + k <= n ? this->rank[j + k] : -1;
        return ri < rj;
      };
      sort(sa.begin(), sa.end(), Compare_SA);
      tmp[sa[0]] = 0;
      for (int i = 1; i <= n; i++) {
        tmp[sa[i]] = tmp[sa[i - 1]] + (Compare_SA(sa[i - 1], sa[i]) ? 1 : 0);
      }
      for (int i = 0; i <= n; i++) {
        this->rank[i] = tmp[i];
      }
    }
  }
  bool Contain(const string &T) {
    int a = 0, b = n;
    while (b - a > 1) {
      int c = (a + b) / 2;
      if (S.compare(sa[c], T.length(), T) < 0)
        a = c;
      else
        b = c;
    }
    return S.compare(sa[b], T.length(), T) == 0;
  }
  vector<int> LCPArray() {
    for (int i = 0; i <= n; i++)
      rank[sa[i]] = i;
    int h = 0;
    vector<int> lcp(n + 1);
    for (int i = 0; i < n; i++) {
      int j = sa[rank[i] - 1];
      if (h > 0)
        h--;
      for (; j + h < n && i + h < n; h++) {
        if (S[j + h] != S[i + h])
          break;
      }
      lcp[rank[i] - 1] = h;
    }
    return lcp;
  }
};
int memo[(int)21e4 + 1];
int main() {
  ll a = 1;
  memo[0] = 1;
  rep1(i, 21e4) memo[i] = a = a * i % mod;
  int n, m, k;
  cin >> n >> m >> k;
  ll ans = 0;
  rep(i, k + 1) {
    ans += (ll)memo[n + m + k * 2] * (n + 1) % mod * (m + 1) % mod *
           pow((ll)memo[i] * memo[n + 1 + i] % mod * memo[k - i] % mod *
                   memo[m + 1 + k - i] % mod,
               mod - 2, mod);
    ans %= mod;
  }
  cout << ans << endl;
}