#![allow(unused_imports, unused_macros, non_snake_case)]
use std::cmp::{max, min, Ordering};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};

//{{{ macros missing in 1.15.1
#[macro_use]
mod macros {
    macro_rules! eprint {
        ($($t:tt)*) => {{
            use ::std::io::Write;
            let _ = write!(::std::io::stderr(), $($t)*);
        }};
    }
    macro_rules! eprintln {
        () => { eprintln!(""); };
        ($($t:tt)*) => {{
            use ::std::io::Write;
            let _ = writeln!(::std::io::stderr(), $($t)*);
        }};
    }
    macro_rules! dbg {
        ($val:expr) => {
            match $val {
                tmp => {
                    eprintln!(
                        "[{}:{}] {} = {:#?}",
                        file!(),
                        line!(),
                        stringify!($val),
                        &tmp
                    );
                    tmp
                }
            }
        };
    }
}
//}}}

fn solve() -> usize {
    let stdin = std::io::stdin();
    let mut sc = Scanner::new(stdin.lock());
    let x: isize = sc.read();
    let y: isize = sc.read();
    let sum = x + y;
    if sum % 3 != 0 {
        return 0;
    }
    let count = sum / 3;
    let diff = x - y;
    if (count + diff) % 2 != 0 {
        return 0;
    }

    let a = (count + diff) / 2;
    let b = count - a;
    if a < 0 || b < 0 {
        return 0;
    }

    let mut answer: Mint107 = 1.into();
    for i in 0..a {
        answer *= (count - i);
        answer /= i + 1;
    }
    answer.val as usize
}
fn run() {
    println!("{}", solve());
}

fn main() {
    std::thread::Builder::new()
        .name("run".to_string())
        .stack_size(1024 * 1024 * 1024)
        .spawn(run)
        .unwrap()
        .join()
        .unwrap()
}

use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops;

/// Trait for `Mint`. `module()` should return prime number.
pub trait Module: Copy + Clone {
    fn module() -> u32;
}

/// One of famous numbers in programming contest. `10^9 + 7`
pub const MOD_107: u32 = 1_000_000_007;
/// One of famous numbers in programming contest. `10^9 + 9`
pub const MOD_109: u32 = 1_000_000_009;
/// One of famous numbers in programming contest. `998_244_353`
pub const MOD_998: u32 = 998_244_353;

/// struct to implement Module trait. it returns `MOD_107`.
#[derive(Debug, Copy, Clone)]
pub struct Mod107;
impl Module for Mod107 {
    fn module() -> u32 {
        MOD_107
    }
}

/// struct to implement Module trait. it returns `MOD_109`.
#[derive(Debug, Copy, Clone)]
pub struct Mod109;
impl Module for Mod109 {
    fn module() -> u32 {
        MOD_109
    }
}

/// struct to implement Module trait. it returns `MOD_998`.
#[derive(Debug, Copy, Clone)]
pub struct Mod998;
impl Module for Mod998 {
    fn module() -> u32 {
        MOD_998
    }
}

/// Wrapper class to compute mod `1_000_000_007` automatically.
///
/// # Examples
/// ```
/// use algonium::math::{Mint107, MOD_107};
/// let x: Mint107 = 1234567.into();
/// let y: Mint107 = 2345678.into();
/// let z = x * y;
/// # // TODO: implement convert to u64
/// assert_eq!(z.val as u64, 1234567u64 * 2345678u64 % MOD_107 as u64);
/// ```
///
pub type Mint107 = Mint<Mod107>;

/// Wrapper class to compute mod `1_000_000_009` automatically.
///
/// # Examples
/// ```
/// use algonium::math::{Mint109, MOD_109};
/// let x: Mint109 = 1234567.into();
/// let y: Mint109 = 2345678.into();
/// let z = x * y;
/// assert_eq!(z.val as u64, 1234567u64 * 2345678u64 % MOD_109 as u64);
/// ```
///
pub type Mint109 = Mint<Mod109>;

/// Wrapper class to compute mod `998_244_353` automatically.
///
/// # Examples
/// ```
/// use algonium::math::{Mint998, MOD_998};
/// let x: Mint998 = 1234567.into();
/// let y: Mint998 = 2345678.into();
/// let z = x * y;
/// assert_eq!(z.val as u64, 1234567u64 * 2345678u64 % MOD_998 as u64);
/// ```
///
pub type Mint998 = Mint<Mod998>;

/// Wrapper class to compute modulo operation.
/// See examples
/// [`Mint107`](type.Mint107.html),
/// [`Mint109`](type.Mint109.html),
/// [`Mint998`](type.Mint998.html)
///
/// # Examples
/// ```
/// use algonium::math::{Mint107, MOD_107};
/// let x: Mint107 = 1234567.into();
/// let y: Mint107 = 2345678.into();
/// let z = x * y;
/// assert_eq!(z.val as u64, 1234567u64 * 2345678u64 % MOD_107 as u64);
/// ```
#[derive(Debug, Copy, Clone, Eq)]
pub struct Mint<M: Module> {
    /// internal value. this is always less than `self.module()`.
    pub val: u32,
    m: PhantomData<M>,
}

impl<M: Module> Mint<M> {
    fn module(self) -> u32 {
        M::module()
    }
    fn new(val: u32) -> Mint<M> {
        assert!(val < M::module());
        Mint {
            val: val,
            m: PhantomData,
        }
    }
}

impl<T: Into<Mint<M>>, M: Module> ops::Add<T> for Mint<M> {
    type Output = Mint<M>;

    fn add(self, other: T) -> Mint<M> {
        let nval = self.val + other.into().val;
        Mint::new(if nval >= self.module() {
            nval - self.module()
        } else {
            nval
        })
    }
}

impl<T: Into<Mint<M>>, M: Module> ops::Sub<T> for Mint<M> {
    type Output = Mint<M>;

    fn sub(self, other: T) -> Mint<M> {
        let nval = self.val + self.module() - other.into().val;
        Mint::new(if nval >= self.module() {
            nval - self.module()
        } else {
            nval
        })
    }
}

impl<T: Into<Mint<M>>, M: Module> ops::Mul<T> for Mint<M> {
    type Output = Mint<M>;

    fn mul(self, other: T) -> Mint<M> {
        let nval = self.val as u64 * other.into().val as u64;
        Mint::new((nval % (self.module() as u64)) as u32)
    }
}

impl<T: Into<Mint<M>>, M: Module> ops::Div<T> for Mint<M> {
    type Output = Mint<M>;

    fn div(self, other: T) -> Mint<M> {
        self * other.into().inv()
    }
}

impl<M: Module> Mint<M> {
    /// Returns number `y` that satisfies `x * y == 1` where `x` is the original value.
    ///
    /// This assumes `module()` returns prime number.
    pub fn inv(self) -> Mint<M> {
        let mut a = self.val as i32;
        let mut b = self.module() as i32;
        let mut u = 1 as i32;
        let mut v = 0 as i32;
        while b != 0 {
            let t = a / b;
            a -= t * b;
            mem::swap(&mut a, &mut b);
            u -= t * v;
            mem::swap(&mut u, &mut v);
        }
        Mint::new(if u < 0 { u + self.module() as i32 } else { u } as u32)
    }
}

impl<M: Module> PartialEq for Mint<M> {
    fn eq(&self, other: &Mint<M>) -> bool {
        self.val == other.val
    }
}

impl<M: Module> fmt::Display for Mint<M> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.val.fmt(f)
    }
}

macro_rules! impl_signed_mint {
    ($($t:ty)*) => ($(
        impl<M: Module> From<$t> for Mint<M> {
            #[inline]
            fn from(x: $t) -> Mint<M> {
                let t = (x as i64) % (M::module() as i64);
                if x >= 0 {
                    Mint{ val: t as u32, m: PhantomData }
                } else {
                    Mint{ val: (M::module() as i64 + t) as u32, m: PhantomData }
                }
            }
        }
    )*)
}

macro_rules! impl_unsigned_mint {
    ($($t:ty)*) => ($(
        impl<M: Module> From<$t> for Mint<M> {
            #[inline]
            fn from(x: $t) -> Mint<M> {
                let t = x as u64 % M::module() as u64;
                Mint::new(t as u32)
            }
        }
    )*)
}

impl_signed_mint! { i8 i16 i32 i64 isize }
impl_unsigned_mint! { u8 u16 u32 u64 usize }

impl<T: Into<Mint<M>>, M: Module> ops::AddAssign<T> for Mint<M> {
    fn add_assign(&mut self, other: T) {
        *self = *self + other.into();
    }
}

impl<T: Into<Mint<M>>, M: Module> ops::SubAssign<T> for Mint<M> {
    fn sub_assign(&mut self, other: T) {
        *self = *self - other.into();
    }
}

impl<T: Into<Mint<M>>, M: Module> ops::MulAssign<T> for Mint<M> {
    fn mul_assign(&mut self, other: T) {
        *self = *self * other.into();
    }
}

impl<T: Into<Mint<M>>, M: Module> ops::DivAssign<T> for Mint<M> {
    fn div_assign(&mut self, other: T) {
        *self = *self / other.into();
    }
}

//{{{ Scanner
pub struct Scanner<R> {
    reader: R,
}

impl<R> Scanner<R> {
    pub fn new(r: R) -> Scanner<R> {
        Scanner { reader: r }
    }
}

fn is_whitespace(b: u8) -> bool {
    b == b' ' || b == b'\n' || b == b'\r' || b == b'\t'
}

impl<R: std::io::Read> Scanner<R> {
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        let buf = std::io::Read::bytes(self.reader.by_ref())
            .map(|b| b.expect("Read failed"))
            .skip_while(|&b| is_whitespace(b))
            .take_while(|&b| !is_whitespace(b))
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error")
    }

    pub fn read_vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }

    pub fn read_chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}
//}}}


Measured memory_bytes: 8572