Problem:
Score : 400 points

Problem Statement

You are given positive integers N and M.

How many sequences a of length N consisting of positive integers satisfy a_1 \times a_2 \times ... \times a_N = M? Find the count modulo 10^9+7.

Here, two sequences a' and a'' are considered different when there exists some i such that a_i' \neq a_i''.

Constraints

All values in input are integers.

1 \leq N \leq 10^5

1 \leq M \leq 10^9

Input

Input is given from Standard Input in the following format:

N M

Output

Print the number of the sequences consisting of positive integers that satisfy the condition, modulo 10^9 + 7.

Sample Input 1

2 6

Sample Output 1

4

Four sequences satisfy the condition: \{a_1, a_2\} = \{1, 6\}, \{2, 3\}, \{3, 2\} and \{6, 1\}.

Sample Input 2

3 12

Sample Output 2

18

Sample Input 3

100000 1000000000

Sample Output 3

957870001

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

use std::collections::HashMap;

const MOD: i64 = 1000000007;


fn main() {
    let comb = Comb::new(1e5 as usize + 100, MOD);
    let (n, m) = read_tuple::<i64>();

    let fact = prime_factorize(m);

    let mut ans:i64 = 1;
    for (_p, count) in fact.iter() {
        ans *= comb.nck((count + n - 1) as usize, *count as usize);
        ans %= MOD;

    }
    println!("{:?}", ans);

}

fn prime_factorize(mut n: i64) -> HashMap<i64, i64> {
    let mut res = HashMap::new();
    let mut i = 2;
    while i * i <= n {
        let mut count = 0;
        while n % i == 0 {
            count += 1;
            n /= i;
        }
        if count > 0 {
            res.insert(i, count);
        }
        i += 1;
    }

    if n != 1 {
        res.insert(n, 1);
    }
    res
}


/// for nCk
pub struct Comb {
    max: usize,
    m: i64,
    fac: Vec<i64>,
    finv: Vec<i64>,
}

impl Comb {
    /// initialize table 
    /// max: maximum that n as nCk takes
    /// m: MOD, a prime number
    /// O(n)
    pub fn new(max: usize, m: i64) -> Comb {
        let n = max;
        let mut fac = Vec::with_capacity(n);
        fac.push(1);
        fac.push(1);
        let mut finv = Vec::with_capacity(n);
        finv.push(1);
        finv.push(1);
        let mut inv = Vec::with_capacity(n);
        inv.push(1);
        inv.push(1);

        for i in 2..n {
            let i = i as i64;
            let new_fac = fac.last().unwrap() * i % m;
            fac.push(new_fac);
            let new_inv = m - inv[(m % i) as usize] * (m / i) % m;
            inv.push(new_inv);
            let new_finv = finv.last().unwrap() * inv.last().unwrap() % m;
            finv.push(new_finv);
        }

        Comb {
            max: max,
            m: m,
            fac: fac,
            finv: finv
        }
    }

    /// nCk
    pub fn nck(&self, n: usize, k: usize) -> i64 {
        // since n, k are usize, do not need to check `n < 0 || k < 0`
        if n < k || n > self.max {
            panic!("Invalid query (n, k) = ({}, {})", n, k);
        } else {
            self.fac[n] * (self.finv[k] * self.finv[n - k] % self.m) % self.m
        }
    }
}



fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().split_whitespace()
        .map(|e| e.parse().ok().unwrap()).collect()
}
fn read_tuple<T: std::str::FromStr + Copy>() -> (T, T) {
    let temp = read_vec();
    (temp[0], temp[1])
}