Problem:
Score : 2100 points

Problem Statement

We have a rectangular parallelepiped of dimensions A×B×C, divided into 1×1×1 small cubes.
The small cubes have coordinates from (0, 0, 0) through (A-1, B-1, C-1).

Let p, q and r be integers. Consider the following set of abc small cubes:

\{(\ (p + i) mod A, (q + j) mod B, (r + k) mod C\ ) | i, j and k are integers satisfying 0 ≤ i < a, 0 ≤ j < b, 0 ≤ k < c \}

A set of small cubes that can be expressed in the above format using some integers p, q and r, is called a torus cuboid of size a×b×c.

Find the number of the sets of torus cuboids of size a×b×c that satisfy the following condition, modulo 10^9+7:

No two torus cuboids in the set have intersection.

The union of all torus cuboids in the set is the whole rectangular parallelepiped of dimensions A×B×C.

Constraints

1 ≤ a < A ≤ 100

1 ≤ b < B ≤ 100

1 ≤ c < C ≤ 100

All input values are integers.

Input

Input is given from Standard Input in the following format:

a b c A B C

Output

Print the number of the sets of torus cuboids of size a×b×c that satisfy the condition, modulo 10^9+7.

Sample Input 1

1 1 1 2 2 2

Sample Output 1

1

Sample Input 2

2 2 2 4 4 4

Sample Output 2

744

Sample Input 3

2 3 4 6 7 8

Sample Output 3

0

Sample Input 4

2 3 4 98 99 100

Sample Output 4

471975164

Solution in Rust (1.15.1) (judge verdict: Accepted)

#[allow(unused_imports)]
use std::cmp::{min,max};
#[allow(unused_imports)]
use std::collections::BTreeMap;

fn main() {
    let (a,b,c,la,lb,lc) = {
        let xs = read_vec_i64();
        (xs[0] as u64, xs[1] as u64, xs[2] as u64, xs[3] as u64, xs[4] as u64, xs[5] as u64)
    };
    if la % a != 0 || lb % b != 0 || lc % c != 0 {
        println!("0");
        return;
    }
    let (na,nb,nc) = (la/a, lb/b, lc/c);
    let (a,b,c) = (Mod(a),Mod(b),Mod(c));
    let slice1 = {
        let mut t = Mod(0);
        t += a * (b * c.pow(nb) + c * b.pow(nc) - b * c).pow(na);
        t += b * (c * a.pow(nc) + a * c.pow(na) - c * a).pow(nb);
        t += c * (a * b.pow(na) + b * a.pow(nb) - a * b).pow(nc);
        t
    };
    let slice2 = {
        let mut t = Mod(0);
        t += a * b * c.pow(na*nb);
        t += b * c * a.pow(nb*nc);
        t += c * a * b.pow(nc*na);
        t
    };
    let slice3 = a * b * c;
    let slice0 = {
        let mut res = Mod(0);
        let comb = combinations(110);
        let mut memo = vec![vec![Mod(0); 110]; 110];
        for p in (1..na+1).rev() {
            for q in (1..nb+1).rev() {
                let mut u = comb[(na-p) as usize][p as usize] * comb[(nb-q) as usize][q as usize] * c.pow((na-p)*(nb-q));
                for i in p..(na+1) {
                    for k in q..(nb+1) {
                        if ! (i == p && k == q) {
                            u -= memo[i as usize][k as usize] * comb[(i-p) as usize][p as usize] * comb[(k-q) as usize][q as usize];
                        }
                    }
                }
                memo[p as usize][q as usize] = u;
                let t = (b.pow(p) + a.pow(q) - Mod(1)).pow(nc) - b.pow(p).pow(nc) - a.pow(q).pow(nc) + Mod(1);
                if ! (p == na && q == nb) {
                    res += a * b * c * t * u;
                }
            }
        }
        res
    };
    let res = (slice1 - slice2 + slice3) + slice0;
    println!("{}", res.0);
}

fn combinations(n: usize) -> Vec<Vec<Mod>> {
    let mut res = vec![vec![Mod(1); n]; n];
    for i in 1..n {
        for k in 1..n {
            res[i][k] = res[i][k-1] + res[i-1][k];
        }
    }
    res
}

const MOD : u64 = 1_000_000_007;
#[derive(Clone,Copy,PartialEq)]
struct Mod (u64);
use std::ops::*;

impl Mod {
    fn pow(self, n: u64) -> Mod {
        if n == 0 {
            return Mod(1);
        }
        let t = self.pow(n/2);
        if n % 2 == 0 {
            t * t
        }
        else {
            t * t * self
        }
    }
}

impl Add for Mod {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Mod((self.0 + rhs.0) % MOD)
    }
}

impl AddAssign for Mod {
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs;
    }
}

impl Sub for Mod {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self::Output {
        Mod((self.0 + MOD - rhs.0 % MOD) % MOD)
    }
}

impl SubAssign for Mod {
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}

impl Mul for Mod {
    type Output = Self;
    fn mul(self, rhs: Self) -> Self::Output {
        Mod(self.0 % MOD * rhs.0 % MOD)
    }
}

impl Div for Mod {
    type Output = Self;
    fn div(self, rhs: Self) -> Self::Output {
        self * rhs.pow(MOD-2)
    }
}

#[allow(dead_code)]
fn read_line() -> String {
    let mut ret = String::new();
    std::io::stdin().read_line(&mut ret).ok();
    ret.pop();
    return ret;
}

#[allow(dead_code)]
fn read_i64() -> i64 {
    let ss = read_line();
    return ss.parse::<i64>().unwrap();
}

#[allow(dead_code)]
fn read_vec_i64() -> Vec<i64> {
    let mut res = vec![];
    let ss = read_line();
    for ts in ss.split_whitespace() {
        let x = ts.parse::<i64>().unwrap();
        res.push(x);
    }
    return res;
}