use std::io::Read;
use std::ops::{Add, Div, Mul};

const MODULO: u64 = 1_000_000_007;

#[derive(Copy, Clone)]
pub struct Rem {
    v: u64,
    modulo: u64,
}

pub struct CombTable {
    factorial: Vec<Rem>,
    fact_inv: Vec<Rem>,
}

impl CombTable {
    pub fn new(val: u64) -> Self {
        let n = val as usize;
        let mut v = Vec::with_capacity(n + 1);
        v.push(Rem::new(1));
        for i in 0..n {
            let prev = v[i];
            v.push(prev * Rem::new((i + 1) as u64));
        }

        let mut vi = vec![Rem::new(0); n + 1];
        vi[n] = v[n].pow(MODULO - 2);
        for i in 0..n {
            vi[n - i - 1] = vi[n - i] * Rem::new((n - i) as u64);
        }
        CombTable {
            factorial: v,
            fact_inv: vi,
        }
    }

    pub fn comb(&self, n: u64, r: u64) -> Rem {
        let nu = n as usize;
        let ru = r as usize;
        self.factorial[nu] * self.fact_inv[ru] * self.fact_inv[nu - ru]
    }
}

pub trait Modulo {
    fn new(x: u64) -> Self;
    fn with_modulo(x: u64, m: u64) -> Self;
    fn pow(&self, n: u64) -> Rem;
    fn to_u64(&self) -> u64;
}

impl Modulo for Rem {
    fn new(x: u64) -> Self {
        Rem {
            v: x,
            modulo: MODULO,
        }
    }

    fn with_modulo(x: u64, m: u64) -> Self {
        Rem { v: x, modulo: m }
    }

    fn pow(&self, n: u64) -> Rem {
        let mut remain_multiple_count = n;
        let mut base_square = Rem::new(self.v);
        let mut current = Rem::new(1);
        while remain_multiple_count > 0 {
            if remain_multiple_count & 1 == 1 {
                current = current * base_square;
            }
            base_square = base_square * base_square;
            remain_multiple_count /= 2;
        }
        current
    }

    fn to_u64(&self) -> u64 {
        self.v
    }
}

impl Div for Rem {
    type Output = Self;
    fn div(self, other: Self) -> Self::Output {
        assert!(self.modulo == other.modulo);
        self * other.pow(self.modulo - 2)
    }
}

impl Mul for Rem {
    type Output = Self;
    fn mul(self, other: Self) -> Self::Output {
        assert!(self.modulo == other.modulo);
        Rem::new(self.v * other.v % self.modulo)
    }
}

impl Add for Rem {
    type Output = Self;
    fn add(self, other: Self) -> Self::Output {
        assert!(self.modulo == other.modulo);
        Rem::new((self.v + other.v) % self.modulo)
    }
}

pub fn read_stdin() -> String {
    let mut s = String::new();
    ::std::io::stdin().read_to_string(&mut s).unwrap();
    s
}

pub trait Parse {
    fn to<T>(&mut self) -> T
    where
        T: std::str::FromStr;
}

impl<'a> Parse for std::str::SplitWhitespace<'a> {
    fn to<T>(&mut self) -> T
    where
        T: std::str::FromStr,
    {
        let word = self.next().unwrap();
        word.parse().ok().unwrap()
    }
}

fn main() {
    let source = read_stdin();
    let mut iter = source.split_whitespace();
    let x: u64 = iter.to();
    let y: u64 = iter.to();
    if (x + y) % 3 != 0 {
        println!("0");
        return;
    }
    let n = (x + y) / 3;
    if x < n || y < n {
        println!("0");
        return;
    }
    let x0 = x - n;
    let y0 = y - n;

    let t = CombTable::new(x0 + y0);
    println!("{}", t.comb(n, x0).to_u64());
}

Measured memory_bytes: 28924