#define NDEBUG

#include <unordered_map>
#include <functional>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cstring>
#include <iomanip>
#include <utility>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <tuple>
#include <set>
#include <map>

// [0, max)
#define FOR0(var, max) for (sl (var) = 0; (var) < (max); ++(var))
// [min, max)
#define FORi(var, min, max) for (sl (var) = (min); (var) < (max); ++(var))
// [min, max)
#define FORi_INV(var, min, max) for (sl (var) = (max) - 1; (var) + 1 > (min); --(var))
#define FORITER(var, iter) for (auto (iter) = (var).begin(); (iter) != (var).end(); (iter)++)
#define FORITER_INV(var, iter) for (auto (iter) = (var).rbegin(); (iter) != (var).rend(); (iter)++)

// a < b < c
#define LTLT(a, b, c) (((a) < (b)) && ((b) < (c)))
// a <= b < c
#define LELT(a, b, c) (((a) <= (b)) && ((b) < (c)))
// a < b <= c
#define LTLE(a, b, c) (((a) < (b)) && ((b) <= (c)))
// a <= b <= c
#define LELE(a, b, c) (((a) <= (b)) && ((b) <= (c)))

#ifndef NDEBUG
#  define MASSERT(cond) m_assert(cond, __LINE__, #cond);
#else
#  define MASSERT(...)
#endif

using namespace std;

using uc = unsigned char;
using ui = unsigned int;
using ul = unsigned long long int;

using sc = signed char;
using si = signed int;
using sl = signed long long int;

using ld = long double;

void m_assert(const bool& cond, const sl& line, const char *condstr) {
  if (!cond) {
    cerr << "Assertion Failed: " << condstr << " at line " << line << endl;
    exit(1);
  }
}

template <class T>
tuple<T, T, T> xgcd(const T& a0, const T& b0) {
  T a = a0, b = b0;
  T x = 0, y = 1, u = 1, v = 0;
  while (a != 0) {
    auto q = b / a;
    auto r = b % a;
    auto m = x - u * q;
    auto n = y - v * q;
    b = a;
    a = r;
    x = u;
    y = v;
    u = m;
    v = n;
  }
  return make_tuple(b, x, y);
}

sl modinv(const sl& a, const sl& m) {
  auto t = xgcd(a, m);
  // assert(std::get<0>(t) == 1)
  auto res = std::get<1>(t) % m;
  if (res < 0) {
    res += m;
  }
  res %= m;
  return res;
}


template <sl Mod>
struct Z_over_nZ{
  sl x;

  Z_over_nZ(const sl& _x) : x(_x % Mod) {
    if (x < 0) {
      x += Mod;
    }
  }

  template <class T>
  Z_over_nZ<Mod> operator+=(const T& y) {
    x += y;
    x %= Mod;
    return *this;
  }

  template <class T>
  Z_over_nZ<Mod> operator-=(const T& y) {
    x -= y;
    x %= Mod;
    return *this;
  }

  template <class T>
  Z_over_nZ<Mod> operator*=(const T& y) {
    x *= y;
    x %= Mod;
    return *this;
  }

  template <class T>
  Z_over_nZ<Mod> operator/=(const T& y) {
    x *= modinv(y, Mod);
    x %= Mod;
    return *this;
  }

  Z_over_nZ<Mod> operator+=(const Z_over_nZ<Mod>& y) {
    return (*this) += y.x;
  }

  Z_over_nZ<Mod> operator-=(const Z_over_nZ<Mod>& y) {
    return (*this) -= y.x;
  }

  Z_over_nZ<Mod> operator*=(const Z_over_nZ<Mod>& y) {
    return (*this) *= y.x;
  }

  Z_over_nZ<Mod> operator/=(const Z_over_nZ<Mod>& y) {
    return (*this) /= y.x;
  }

  template <class T>
  Z_over_nZ<Mod> operator+(const T& y) const {
    return Z_over_nZ(*this) += y;
  }

  template <class T>
  Z_over_nZ<Mod> operator-(const T& y) const {
    return Z_over_nZ(*this) -= y;
  }

  template <class T>
  Z_over_nZ<Mod> operator*(const T& y) const {
    return Z_over_nZ(*this) *= y;
  }

  template <class T>
  Z_over_nZ<Mod> operator/(const T& y) const {
    return Z_over_nZ(*this) /= y;
  }

  Z_over_nZ<Mod> operator-() const {
    return Z_over_nZ(Mod - x);
  }

  template <class T>
  bool operator!=(const T& y) const {
    return !(*this == y);
  }

  template <class T>
  bool operator==(const T& y) const {
    return (x - y) % Mod == 0;
  }

  bool operator==(const Z_over_nZ<Mod>& y) const {
    return (x - y.x) % Mod == 0;
  }

  template <class T>
  Z_over_nZ<Mod> operator=(const T& y) {
    x = y;
    return *this;
  }

  Z_over_nZ<Mod> operator=(const Z_over_nZ& y) {
    x = y.x;
    return *this;
  }

  template <class T>
  bool operator<(const T& other) {
    return x < other;
  }
};

template <sl Mod>
ostream& operator<<(ostream& os, const Z_over_nZ<Mod>& x) {
  os << x.x;
  return os;
}

template <class T, sl Mod>
bool operator<(const T& lhs, const Z_over_nZ<Mod>& rhs) {
  return lhs < rhs.x;
}

template <class T>
T factorial(const T& n) {
  T res = 1;
  FOR0(i, n) {
    res *= i + 1;
  }
  return res;
}

template <class T>
T permutation(const T& n, const T& m) {
  return factorial(n) / factorial(n - m);
}

template <class T>
T combination(const T& n, const T& m) {
  return permutation(n, m) / factorial(m);
}

using Zmod1000000007 = Z_over_nZ<1000000007>;

static sl X, Y;
const static sl XMAX = 1000000;
const static sl YMAX = 1000000;

void solve(void) {
  if ((X + Y) % 3 != 0) {
    cout << 0 << endl;
    return;
  }
  si n_cand = -(Y - 2 * X) / 3;
  si m_cand = -(X - 2 * Y) / 3;
  if (n_cand < 0 || m_cand < 0) {
    cout << 0 << endl;
    return;
  }
  Zmod1000000007 n = n_cand;
  Zmod1000000007 m = m_cand;
  cout << combination(n + m, n) << endl;
}

int main(void) {
  cin >> X >> Y;
  solve();
  return 0;
}

Measured memory_bytes: 256