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 Rust (1.15.1) (judge verdict: Accepted)

use std::io::Write;
use std::ops::{Add, Mul, Sub};

#[allow(unused)]
macro_rules! debug {
    ($($format:tt)*) => (write!(std::io::stderr(), $($format)*).unwrap());
}
#[allow(unused)]
macro_rules! debugln {
    ($($format:tt)*) => (writeln!(std::io::stderr(), $($format)*).unwrap());
}

fn main() {
    let (x, y): (isize, isize) = {
        let mut s = String::new();
        std::io::stdin().read_line(&mut s).unwrap();
        let s = s.trim_right().to_owned();
        let mut ws = s.split_whitespace();
        let a = ws.next().unwrap().parse().unwrap();
        let b = ws.next().unwrap().parse().unwrap();
        (a, b)
    };

    println!("{}", solve(x, y));
}

fn solve(x: isize, y: isize) -> usize {
    let xx3 = 2 * x - y;
    let yy3 = -x + 2 * y;
    debugln!("{:?}", (xx3, yy3));
    if !(xx3 % 3 == 0 && yy3 % 3 == 0 && xx3 >= 0 && yy3 >= 0) {
        return 0;
    }

    let xx = xx3 / 3;
    let yy = yy3 / 3;

    Modulo::binom_coef(xx + yy, xx).0
}

fn positive_rem(a: isize, b: usize) -> usize {
    let b = b as isize;
    let mut value = a % b;
    if value < 0 {
        value += b;
    }
    // TODO: TryFrom
    value as usize
}

/// Return (x, y) s.t. ax + by = d where d = gcd(a, b)
fn ext_gcd(a: usize, b: usize) -> (isize, isize) {
    if b == 0 {
        return (1, 0);
    }

    let q = (a / b) as isize;
    let r = a % b;
    let (x1, y1) = ext_gcd(b, r);
    (y1, x1 - q * y1)
}

#[derive(Debug, Copy, Clone)]
struct Modulo(usize);

const MODULO: usize = 1000000000 + 7;

impl Modulo {
    fn from_isize(n: isize) -> Modulo {
        // TODO: use TryFrom
        Modulo(positive_rem(n, MODULO as usize))
    }

    fn pow(self, p: usize) -> Modulo {
        if self == Modulo(0) {
            return Modulo(0);
        }
        if p == 0 {
            return Modulo(1);
        }

        if p % 2 == 0 {
            let half = self.pow(p / 2);
            half * half
        } else {
            self.pow(p - 1) * self
        }
    }

    // when MODULO is prime
    fn inv(self) -> Modulo {
        let (x, _) = ext_gcd(self.0 as usize, MODULO as usize);
        Modulo::from_isize(x)
    }

    // when MODULO is prime
    fn binom_coef(n: isize, k: isize) -> Modulo {
        let mut ret = Modulo::from_isize(1);
        for i in 1..(k + 1) {
            ret = ret * Modulo::from_isize(n - i + 1) * Modulo::from_isize(i).inv();
        }
        ret
    }
}

impl Add for Modulo {
    type Output = Modulo;

    fn add(self, other: Modulo) -> Modulo {
        Modulo((self.0 + other.0) % MODULO)
    }
}

impl Sub for Modulo {
    type Output = Modulo;

    fn sub(self, other: Modulo) -> Modulo {
        Modulo(positive_rem(
            self.0 as isize - other.0 as isize,
            MODULO as usize,
        ))
    }
}

impl Mul for Modulo {
    type Output = Modulo;

    fn mul(self, other: Modulo) -> Modulo {
        Modulo((self.0 * other.0) % MODULO)
    }
}

impl PartialEq for Modulo {
    fn eq(&self, &other: &Self) -> bool {
        self.0 == other.0
    }
}

impl Eq for Modulo {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn eq() {
        assert_eq!(
            Modulo::from_isize(1),
            Modulo::from_isize((1 + MODULO) as isize)
        );
    }

    #[test]
    fn add1() {
        assert_eq!(Modulo(1), Modulo(6) + Modulo(6));
    }

    #[test]
    fn add2() {
        assert_eq!(Modulo(0), Modulo(5) + Modulo(6));
    }

    #[test]
    fn sub1() {
        assert_eq!(Modulo(2), Modulo(3) - Modulo(1));
    }

    #[test]
    fn sub2() {
        assert_eq!(Modulo(10), Modulo(1) - Modulo(2));
    }

    #[test]
    fn mul() {
        assert_eq!(Modulo(3), Modulo(5) * Modulo(5));
    }

    #[test]
    fn pow() {
        assert_eq!(Modulo(5), Modulo(7).pow(2));
    }

    #[test]
    fn inv() {
        assert_eq!(Modulo(1), Modulo(2) * Modulo(2).inv());
        assert_eq!(Modulo(1), Modulo(3) * Modulo(3).inv());
    }

    #[test]
    fn ext_gcd_test() {
        let a = 12isize;
        let b = 18isize;
        let (x, y) = ext_gcd(a as usize, b as usize);
        assert_eq!(6, a * x + b * y);

        let a = 4isize;
        let b = 12isize;
        let (x, y) = ext_gcd(a as usize, b as usize);
        assert_eq!(4, a * x + b * y);
    }

    #[test]
    fn binom_coef() {
        assert_eq!(Modulo(6), Modulo::binom_coef(4, 2));
    }
}