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 C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
using System.Text;//テキストの高速出力に必要
class Program
{
static bool[] isPrimes = makePrimeList(100000);//i-1が素数かどうか
static long factMax = 200000;//nCkにおけるnの最大値
static long[] factorials = new long[factMax+1];//i!(mod p)を先にメモ
static long[] factorialRs = new long[factMax+1];//i!^-1(mod p), pは素数

	static void Main()
	{
		long p = 1000000007;
		string[] input = Console.ReadLine().Split(' ');
		long m = long.Parse(input[0]);
		int n = int.Parse(input[1]);
		long answer = 1;
    factorials[0] = 1;
		factorialRs[factMax] = DivideModFactorial(factMax,p);
		for(long i = 1; i <= factMax; i++)
		{
		factorials[i] = (factorials[i-1]*i)%p;//i!(mod p)
		factorialRs[factMax-i] = (factorialRs[factMax+1-i]*(factMax+1-i))%p;//逆元も先にメモ
		}

    List<long> factList = Factoring(n);
    int countMemo = 0;
    for(int i = 0; i < factList.Count(); i++)
    {
      if(i == 0) countMemo++;
      else if(factList[i] == factList[i-1]) countMemo++;
      else
      {
        answer *= factorials[countMemo+(m-1)];
        answer %= p;
        answer *= factorialRs[countMemo];
        answer %= p;
        answer *= factorialRs[m-1];
        answer %= p;
        countMemo = 1;
      }
    }

    if(countMemo > 0)
    {
      answer *= factorials[countMemo+(m-1)];
      answer %= p;
      answer *= factorialRs[countMemo];
      answer %= p;
      answer *= factorialRs[m-1];
      answer %= p;
    }

    //Console.WriteLine(answer+"a");
    long answerMulMemo = 0;
    if(n > 0)
    {
      for(int i = 0; i <= m; i+=2)
      {
        //Console.WriteLine(answer);
        answerMulMemo += Comb(m,i,p);
        answerMulMemo %= p;
      }
    }else
    {
      for(int i = 1; i <= m; i+=2)
      {
        answerMulMemo += Comb(m,i,p);
        answerMulMemo %= p;
      }
    }
    //answer *= answerMulMemo;
    answer %= p;

		Console.WriteLine(answer);
	}

  static List<long> Factoring(long originalNum)
  {//makePrimeListによるisPrimesを用いて、引数をO(√n)で素因数分解。リストには同じ数も含む。
  //例えば1は{},12は{2,2,3},17は{17}を返す。
    List<long> answers = new List<long>();
    for(long i = 2; i <= Math.Sqrt(originalNum); i++)
    {
      if(!isPrimes[i-1]) continue;//素数でないとき
      else
      {
        while(originalNum % i == 0)
        {
          originalNum /= i;
          answers.Add(i);
        }
      }
    }
    if(originalNum != 1) answers.Add(originalNum);
    return answers;
  }

  static bool[] makePrimeList(long maxPrime)
  {//「引数1以上」max以下の素数判定を、エラトステネスの篩を用いてO(n)。
    bool[] isPrimes = new bool[maxPrime];//素数リスト
    isPrimes[0] = false;//1は素数でないのでfalse
    for(long i = 1; i < maxPrime; i++) isPrimes[i] = true;//素数と仮定してtrue
    
    for(long i = 2; i <= Math.Sqrt(maxPrime); i++)
    {
      if(isPrimes[i-1])
      {
        for (long j = i*2; j <= maxPrime; j+=i)
        {
          isPrimes[j-1] = false;//素数でないのでfalse
        }
      }
    }

    return isPrimes;
  }

  static long MathPow(long x, long a)//戻り値はx^a。O(loga)
  {
    long num = 2;
    long answer = 1;
    long check = a;
    long memo = x;
  
    while(check > 0)
    {
      if(check % num == num / 2)
      {
        check -= num / 2;
        answer *= memo;
      }
    memo *= memo;
    num *= 2;
    }
    return answer;
  }

  static long DivideMod(long x, long a, long p)//戻り値はx^a(mod p)。O(loga)
  {
    long num = 2;
    long answer = 1;
    long check = a;
    long memo = x%p;
    
    while(check > 0)
    {
      if(check % num == num / 2)
      {
        check -= num / 2;
        answer *= memo;
        answer %= p;
      }
    memo *= memo;
    memo %= p;
    num *= 2;
    }
    return answer;
  }

  static long DivideModReverse(long x, long p)//戻り値はx^-1(mod p), pは素数。O(logp)
  {
    long answer = DivideMod(x, p-2, p);
    return answer;
  }

  static long ModFactorial(long x, long p)//戻り値はx!(mod p)
  {
    long answer = 1;
    for(int i = 2; i <= x; i++)
    {
      answer *= i;
      answer %= p;
    }
    return answer;
  }

  static long DivideModFactorial(long x, long p)//戻り値はx!^-1(mod p), pは素数
  {
    long answer = 1;
    for(long i = x; i >= 2; i--)
    {
      answer *= DivideModReverse(i, p);
      answer %= p;
    }
    return answer;
  }

  static long Comb(long a, long b, long p)//戻り値は組み合わせC(a,b)のmod p
  {
    if(a-b < 0) return 0;//引数a-bが負なら0を返す
    long answer = 1;
    answer *= factorials[a];
    answer %= p;
    answer *= factorialRs[a-b];
    answer %= p;
    answer *= factorialRs[b];
    answer %= p;
    return answer;
  }

  
}