// https://atcoder.jp/contests/past-sample/tasks/abc129_d

// config 

const int __SETW__ = 6;

// IO
#include <iostream>      // cin, cout
#include <iomanip>       // setw
// MATH & ALGROTHM
#include <cmath>
#include <complex>
#include <numeric>
#include <algorithm>
// CONTAINER 
#include <tuple>
#include <string>      
#include <vector>
#include <deque>
#include <queue>  
#include <stack>
#include <map>       
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <list>
// FUNCTION
#include <functional>
// META
#include <type_traits>
 
/////// 
using std::cin;
using std::cout;
using std::endl;

using INT = long long int;
const INT INF = INT(1) << 60;

#define FOR(i, N) for( INT i = 0; i < N; i++ )
#define RANGE(v) begin(v), end(v)

using VEC = std::vector<INT>;
using VECVEC = std::vector<VEC>;

template< class T >
T safe_get ( const std::vector<T>& v, INT idx, T def = -1 ){
    if( idx < 0 || v.size() <= idx ){
        return def;
    } else {
        return v[idx];
    }
}
template< class T >
T safe_get ( const std::vector< std::vector<T> >& vv, INT idx1, INT idx2, T def = -1 ){
    if( idx1 < 0 || vv.size() <= idx1 ){
        return def;
    } else {
        return safe_get(vv[idx1], idx2, def );
    }
}

template< class T, class F >
inline bool ANY( T sequence, F func ){
    for(  auto&& t : sequence ){
        if( func(t) ){ return true; }
    }
    return false;
}
template< class T, class F >
inline bool ALL( T sequence, F func ){
    for(  auto&& t : sequence ){
        if( ! func(t) ){ return false; }
    }
    return true;
}

template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::priority_queue<T>& rhs ){
    std::queue<T> copy = rhs;
    while( !copy.empty() ){
        lhs << std::setw(__SETW__) << copy.front() << " ";
        copy.pop();
    }
    return lhs;
}
template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::queue<T>& rhs ){
    std::queue<T> copy = rhs;
    while( !copy.empty() ){
        lhs << std::setw(__SETW__) << copy.front() << " ";
        copy.pop();
    }
    return lhs;
}
template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::stack<T>& rhs ){
    std::stack<T> copy = rhs;
    while( !copy.empty() ){
        lhs << std::setw(__SETW__) << copy.top() << " ";
        copy.pop();
    }
    return lhs;
}

template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::vector< std::vector<T> >& rhs ){
    for( auto&& v : rhs ){
        lhs << v << endl;
    }
    return lhs;
}
template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::vector<T>& rhs ){
    for( auto&& t : rhs ){
        lhs << std::setw(__SETW__) << t << " ";
    }
    return lhs;
}
template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::list<T>& rhs ){
    for( auto&& t : rhs ){
        lhs << std::setw(__SETW__) << t << " ";
    }
    return lhs;
}

template< class T1, class T2 >
std::ostream& operator<< ( std::ostream& lhs, const std::map<T1, T2>& rhs ){
    for( auto&& m : rhs ){
        lhs << std::setw(__SETW__) << m.first << ":" << std::setw(__SETW__) << m.second << endl;
    }
    return lhs;
}
template< class T1, class T2 >
std::ostream& operator<< ( std::ostream& lhs, const std::multimap<T1, T2>& rhs ){
    for( auto&& m : rhs ){
        lhs << std::setw(__SETW__) << m.first << ":" << std::setw(__SETW__) << m.second << endl;
    }
    return lhs;
}
template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::set<T>& rhs ){
    for( auto&& t : rhs ){
        lhs << std::setw(__SETW__) << t << " ";
    }
    return lhs;
}
template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::multiset<T>& rhs ){
    for( auto&& t : rhs ){
        lhs << std::setw(__SETW__) << t << " ";
    }
    return lhs;
}

template< class T >
std::ostream& operator<< ( std::ostream& lhs, const std::complex<T>& rhs ){
    std::streamsize ss = lhs.precision();
    lhs << "(" << std::setw(5) << std::setprecision(4) << rhs.real() << ","
               << std::setw(5) << std::setprecision(4) << rhs.imag() << ") ";
    lhs.precision(ss);
    return lhs;
}
template< class T1, class T2 >
std::ostream& operator<< ( std::ostream& lhs, const std::pair<T1, T2>& rhs ){
    lhs << "(" << rhs.first << "," << rhs.second << ")";
    return lhs;
}

template< class T >
T chmax( T& lhs, T& rhs){
    lhs = std::max( lhs, rhs);
    return lhs;
}
template< class T >
T chmin( T& lhs, T& rhs){
    lhs = std::min( lhs, rhs);
    return lhs;
}

class ModInt{
    public:
    INT a, Modulus;

    constexpr ModInt(const INT x, const INT Modulus) noexcept : Modulus(Modulus), a(x % Modulus) {}
    constexpr INT &value() noexcept { return a; }
    constexpr const INT &value() const noexcept { return a; }
    constexpr ModInt operator+(const ModInt rhs) const noexcept {
        return ModInt(*this) += rhs;
    }
    constexpr ModInt operator-(const ModInt rhs) const noexcept {
        return ModInt(*this) -= rhs;
    }
    constexpr ModInt operator*(const ModInt rhs) const noexcept {
        return ModInt(*this) *= rhs;
    }
    constexpr ModInt operator/(const ModInt rhs) const noexcept {
        return ModInt(*this) /= rhs;
    }
    constexpr ModInt &operator+=(const ModInt rhs) noexcept {
        a += rhs.a;
        if (a >= Modulus) {
        a -= Modulus;
        }
        return *this;
    }
    constexpr ModInt &operator-=(const ModInt rhs) noexcept {
        if (a < rhs.a) {
        a += Modulus;
        }
        a -= rhs.a;
        return *this;
    }
    constexpr ModInt &operator*=(const ModInt rhs) noexcept {
        a = a * rhs.a % Modulus;
        return *this;
    }
    constexpr ModInt &operator/=(ModInt rhs) noexcept {
        INT exp = Modulus - 2;
        while (exp) {
        if (exp % 2) {
            *this *= rhs;
        }
        rhs *= rhs;
        exp /= 2;
        }
        return *this;
    }
};

int main(){
    INT X, Y;
    cin >> X >> Y;

    if( (X+Y) % 3 != 0 ){
        cout << 0 << endl;
        return 0;
    }

    INT I, J;
    I = -X/3 + 2*Y/3;
    J = 2*X/3 - Y/3;

    if( I < 0 || J < 0 ){
        cout << 0 << endl;
        return 0;
    }

    ModInt ans(1, 1000000007LL );
    FOR(i, I+J){
        ans *= ModInt(i+1, 1000000007LL) ;
    }
    FOR(i, I){
        ans /= ModInt(i+1, 1000000007LL) ;
    }
    FOR(i, J){
        ans /= ModInt(i+1, 1000000007LL) ;
    }

    cout << ans.a << endl;

    return 0;
}


Measured memory_bytes: 256