Problem:
Score : 400 points

Problem Statement

There is a knight - the chess piece - at the origin (0, 0) of a two-dimensional grid.

When the knight is at the square (i, j), it can be moved to either (i+1,j+2) or (i+2, j+1).

In how many ways can the knight reach the square (X, Y)?

Find the number of ways modulo 10^9 + 7.

Constraints

1 \leq X \leq 10^6

1 \leq Y \leq 10^6

All values in input are integers.

Input

Input is given from Standard Input in the following format:

X Y

Output

Print the number of ways for the knight to reach (X, Y) from (0, 0), modulo 10^9 + 7.

Sample Input 1

3 3

Sample Output 1

2

There are two ways: (0,0) \to (1,2) \to (3,3) and (0,0) \to (2,1) \to (3,3).

Sample Input 2

2 2

Sample Output 2

0

The knight cannot reach (2,2).

Sample Input 3

999999 999999

Sample Output 3

151840682

Print the number of ways modulo 10^9 + 7.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
#include <boost/algorithm/string/join.hpp>
#include <boost/range/irange.hpp>
#include <boost/multiprecision/cpp_int.hpp>
using namespace std;
using boost::irange;
using boost::algorithm::join;

typedef long long ll;
typedef unsigned long long ull;
//typedef long double ld;

typedef map<int, int> mii;
typedef pair<int, int> pii;
typedef pair<double,double> pdd;
typedef set<int> si;
typedef set<ll> sll;
typedef vector<int> vi;
typedef vector<pair<int, int > > vii;
typedef vector<ll> vll;
typedef vector<double> vd;
typedef vector<vi> vvi;
typedef vector<vii> vvii;
typedef vector<vll> vvll;

constexpr ll MOD = 1e9+7;
//template<typename T>constexpr auto inf=numeric_limits<T>::max()/4;
//constexpr int INF=inf<int>;
//constexpr ll LINF=inf<ll>;

#define Sort(x) sort(begin(x),end(x))
#define Reverse(x) reverse(begin(x),end(x))
#define ABS(a,b) ((a)<(b)?(b)-(a):(a)-(b))
#define nbit(n) (1ull<<(n))
#define _ol3(_1,_2,_3,name,...)name
#define _rep(i,n)_repi(i,0,n)
#define _repi(i,a,b)for(int i=a,i##_l=(b);i<i##_l;++i)
#define REP(...) _ol3(__VA_ARGS__,_repi,_rep,)(__VA_ARGS__)
#define REPR(i,n) for(int i=n-1;i>=0;--i)
#define REPA(i,v) REP(i,(v).size())

// sort(begin(x), end(x), greater<ll>());
// lower_bound(a.begin(), a.end(), val): a[i] ≥ valである最左の位置
// upper_bound(a.begin(), a.end(), val): a[i] > valである最左の位置

// Returns minimum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmin(T& a, T b) {
  if (a > b) {
    a = b;
  }
  return a;
}

// Returns maximum of a and b.
// If a is less b, a is set to b.
template<typename T>
T chmax(T& a, T b) {
  if (a < b) {
    a = b;
  }
  return a;
}

template <typename T>
void dumpContents(const T& v, const string& msg)
{
  cerr << "### " << msg << " ###\n";
  for (const auto& x : v) {
    cerr << x << " ";
  }
  cerr << endl;
}

struct before_main_function {
  before_main_function() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout<<setprecision(20)<<fixed;
    #define endl "\n"
  }
} before_main_function;

/**
 * PrimeTools class provides functions dealing with primes, calculating primes
 * upto N in advance.
 *
 * Note that when you only deal with factors, N <- sqrt(N) would be enough.
 */
class PrimeTools {
  const ll N;
  vll primes;

  void eratosthenesPrimes(const ll N)
  {
    vll tmp(N+1, 1);
    tmp[0] = 0;
    tmp[1] = 0;
    tmp[2] = 1;

    if (N<=1) return;
    primes.push_back(2);
    if (N<=2) return;

    for(ll i=3; i<=N; i+=2) {
      if (tmp[i] == 0) continue;
      primes.push_back(i);
      if (N<i*i) continue;
      for (ll k=i+i; k<=N; k+=i) {
        tmp[k]=0;
      }
    }
  }

public:

  PrimeTools(const ll _N=10000000)
    : N(_N) {

    eratosthenesPrimes(N);
  }

  typedef typename vll::iterator iterator;
  typedef typename vll::const_iterator const_iterator;

  inline iterator begin() noexcept { return primes.begin(); };
  inline const_iterator cbegin() const noexcept { return primes.cbegin(); };
  inline iterator end() noexcept { return primes.end(); };
  inline const_iterator cend() const noexcept { return primes.cend(); };

  bool isPrime(const ll n) const {
    return binary_search(cbegin(), cend(), n);
  }

  // A return set
  // * does not include 1
  // * includes n
  //
  // 2 -> {2}
  // 6 -> {2, 3}
  // 16 -> {2}  // uniqueなもののみ
  //
  // 約数を知りたい場合は、divisors()
  sll uniqueFactors(ll n) const {
    sll ret;
    if (n==1) return ret;

    const auto itend = upper_bound(cbegin(), cend(), sqrt(n));

    for (auto it = primes.begin(); it!=itend; it++) {
      const ll p = *it;
      if (n==1) break;
      if (n % p == 0) {
        ret.insert(p);
        while (n % p == 0) {
          n /= p;
        }
      }
    }
    if (n>1) ret.insert(n);
    return ret;
  }

  map<ll,ll> factorExponents(ll n) const {
    map<ll, ll> ret;
    if (n==1) return ret;

    for (const ll p : uniqueFactors(n)) {
      if (n % p == 0) {
        ret.insert(make_pair(p,0));
        while (n % p == 0) {
          n /= p;
          ret[p] += 1;
        }
      }
    }
    if (ret.empty()) ret.insert(make_pair(n,1)); // n is prime
    return ret;
  }

  /*
   * Rutuns a vector of sorted products of b^0, b^1, ... , b^n"
   */
  static vll makeProducts(const ll base, const ll n) {
    vll ret;
    ret.reserve(n+1);
    ret.push_back(1);
    for (ll i=1; i<=n; ++i) {
      ret.push_back(ret.back()*base);
    }
    return ret;
  }

  /*
   * Returns a sorted sequence of divisors of n.
   * For example, 12 => (1 2 3 4 6 12)"
   */
  vll divisors(long n) const {
    vll ret;
    ret.push_back(1);
    for (const auto& kv : factorExponents(n)) {
      const vll products = makeProducts(kv.first, kv.second);
      vll tmp;
      tmp.reserve(ret.size()*products.size());
      for (const ll x : ret) {
        for (const ll y : products) {
          tmp.push_back(x*y);
        }
      }
      ret.swap(tmp);
    }
    std::sort(ret.begin(), ret.end());
    return ret;
  }
};

// Calculate aCb mod 1000000007 in O(SIZE)
template<int SIZE>
struct Combination {
  static constexpr long long mod = MOD;

  long long inv[SIZE+1];           // modでの逆元
  long long factorial[SIZE+1];     // modでの階乗
  long long invfactorial[SIZE+1];  // modでの階乗の逆元

  Combination() {
    inv[1] = 1;
    // po()を使えばO(N log p)だが、O(N)で計算するアルゴリズム
    for (int i=2; i<=SIZE; i++) {
      inv[i] = mod - (mod/i)*inv[mod%i] % mod;
    }

    factorial[0] = invfactorial[0] = 1;
    for (int i=1; i<=SIZE; i++){
      factorial[i] = factorial[i-1] * i % mod;
      invfactorial[i] = invfactorial[i-1] * inv[i] % mod;
    }
  }

  long long operator()(long long a, long long b) const {
    if (b<0 || a<b) return 0;

    return (invfactorial[b] * invfactorial[a-b]) % mod * factorial[a] % mod;
  }
};

Combination<1000100> combi;

struct mint {
  ll x;

  mint(ll _x=0) : x(_x%MOD) {}

  mint& operator+=(const mint a) {
    if ((x += a.x) >= MOD) x -= MOD;
    return *this;
  }

  mint& operator-=(const mint a) {
    if ((x += MOD-a.x) >= MOD) x -= MOD;
    return *this;
  }

  mint& operator*=(const mint a) {
    (x *= a.x) %= MOD;
    return *this;
  }

  mint operator+=(const mint a) const {
    mint ret(*this);
    return ret+=a;
  }

  mint operator-=(const mint a) const {
    mint ret(*this);
    return ret-=a;
  }

  mint operator*=(const mint a) const {
    mint ret(*this);
    return ret*=a;
  }

  mint& operator/=(const mint a) {
    return (*this) *= a.inv();
  }

  mint operator+(const mint a) const {
    mint ret(*this);
    return ret += a;
  }

  mint operator-(const mint a) const {
    mint ret(*this);
    return ret -= a;
  }

  mint operator*(const mint a) const {
    mint ret(*this);
    return ret *= a;
  }
  mint operator/(const mint a) const {
    mint ret(*this);
    return ret/=a;
  }

  mint pow(ll t) const {
    if (!t) return 1;
    mint a = pow(t>>1);
    a *= a;
    if (t&1) a *= *this;
    return a;
  }

  mint inv() const {
    // MOD should be a prime
    return pow(MOD-2);
  }

};

ostream& operator<<(ostream& os, const mint& a) {
    os << a.x;
    return os;
}
// ========== end of template ==========

int main(int argc, char** argv) {
  int X, Y;
  cin >> X >> Y;

  mint ret = 0;
  REP(x, X+1) {
    // (1,2)をx回
    // (2,1)をy回

    if ((X-x)%2==1) continue;
    int y = (X-x)/2;
    if (Y != 2*x + y) continue;

    ret += combi(x+y, x);
  }

  cout << ret << endl;
  return 0;
}