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 Kotlin (1.0.0) (judge verdict: Accepted)

import java.io.IOException
import java.io.InputStream
import java.io.PrintWriter
import java.util.*

fun main(args: Array<String>) {
    val sc = Scanner(System.`in`)
    val out = PrintWriter(System.out)
    val (n, m) = sc.nextInts(2)
    val mod = 1000000007
    val factors = factors(m)
    val combi = Combination(n + factors.values.sum(), mod)
    var ans = 1
    factors.values.forEach { ans = (ans * combi.get(n + it - 1, it) % mod).toInt() }
    out.println(ans)
    out.close()
}

fun factors(n: Int): Map<Int, Int> {
    val factors = mutableMapOf<Int, Int>()
    var tmp = n
    var i = 2
    while (i * i <= tmp) {
        while (tmp % i == 0) {
            factors[i] = factors.getOrElse(i) { 0 } + 1
            tmp /= i
        }
        i++
    }
    if (tmp > 1) factors[tmp] = 1
    return factors
}

class Combination(n: Int, private val mod: Int) {

    private val fact = LongArray(n + 1)
    private val inv = LongArray(n + 1)
    private val invfact = LongArray(n + 1)

    init {
        inv[1] = 1
        for (i in 2 until inv.size) {
            inv[i] = inv[mod % i] * (mod - mod / i) % mod
        }

        fact[0] = 1
        invfact[0] = 1
        for (i in 1 until inv.size) {
            fact[i] = i * fact[i - 1] % mod
            invfact[i] = inv[i] * invfact[i - 1] % mod
        }
    }

    fun get(n: Int, r: Int): Long {
        return if (n < r) 0 else fact[n] * invfact[n - r] % mod * invfact[r] % mod
    }

}

class Scanner(private val `in`: InputStream) {
    private val buffer = ByteArray(1024)
    private var ptr = 0
    private var buflen = 0

    private fun hasNextByte(): Boolean {
        if (ptr < buflen) return true
        else {
            ptr = 0
            try {
                buflen = `in`.read(buffer)
            } catch (e: IOException) {
                e.printStackTrace()
            }
            if (buflen <= 0) return false
        }
        return true
    }

    private fun readByte(): Byte {
        return if (hasNextByte()) buffer[ptr++] else -1
    }

    private fun isPrintableChar(c: Char): Boolean {
        return c in '!'..'~'
    }

    private fun skipUnprintable() {
        while (hasNextByte() && !isPrintableChar(buffer[ptr].toChar())) ptr++
    }

    fun hasNext(): Boolean {
        skipUnprintable()
        return hasNextByte()
    }

    fun next(): String {
        if (!hasNext()) throw NoSuchElementException()
        val sb = StringBuilder()
        var b = readByte()
        while (isPrintableChar(b.toChar())) {
            sb.appendCodePoint(b.toInt())
            b = readByte()
        }
        return sb.toString()
    }

    fun nextInt(): Int {
        if (!hasNext()) throw NoSuchElementException()
        var n = 0
        var minus = false
        var b = readByte()
        if (b.toChar() == '-') {
            minus = true
            b = readByte()
        }
        if (b.toChar() !in '0'..'9') throw NumberFormatException()
        while (true) {
            if (b.toChar() in '0'..'9') {
                n *= 10
                n += b - '0'.toByte()
            } else return if (b.toInt() == -1 || !isPrintableChar(b.toChar())) {
                if (minus) -n else n
            } else {
                throw NumberFormatException()
            }
            b = readByte()
        }
    }

    fun nextInts(n: Int): Array<Int> {
        return Array(n) { nextInt() }
    }

    fun nextIntArray(n: Int): IntArray {
        return IntArray(n) { nextInt() }
    }

    fun nextIntArrays(n: Int, m: Int): Array<IntArray> {
        val arrays = Array(m) { IntArray(n) }
        for (i in 0 until n) {
            for (j in 0 until m) {
                arrays[j][i] = nextInt()
            }
        }
        return arrays
    }

    fun nextLong(): Long {
        if (!hasNext()) throw NoSuchElementException()
        var n: Long = 0
        var minus = false
        var b = readByte()
        if (b == '-'.toByte()) {
            minus = true
            b = readByte()
        }
        if (b.toChar() !in '0'..'9') throw NumberFormatException()
        while (true) {
            if (b.toChar() in '0'..'9') {
                n *= 10
                n += (b - '0'.toByte()).toLong()
            } else return if (b.toInt() == -1 || !isPrintableChar(b.toChar())) {
                if (minus) -n else n
            } else {
                throw NumberFormatException()
            }
            b = readByte()
        }
    }

    fun nextLongs(n: Int): Array<Long> {
        return Array(n) { nextLong() }
    }

    fun nextLongArray(n: Int): LongArray {
        return LongArray(n) { nextLong() }
    }

    fun nextLongArrays(n: Int, m: Int): Array<LongArray> {
        val arrays = Array(m) { LongArray(n) }
        for (i in 0 until n) {
            for (j in 0 until m) {
                arrays[j][i] = nextLong()
            }
        }
        return arrays
    }
}