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 Common Lisp (SBCL 1.1.14) (judge verdict: Accepted)

;; -*- coding: utf-8 -*-
#-(or child-sbcl swank)
(quit
 :unix-status
 (process-exit-code
  (run-program *runtime-pathname*
               '("--control-stack-size" "32MB"
                 "--noinform" "--disable-ldb" "--lose-on-corruption" "--end-runtime-options"
                 "--eval" "(push :child-sbcl *features*)"
                 "--script" #.(namestring *load-pathname*))
               :output t :error t :input t)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defparameter OPT
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0)))
  #+swank (progn (ql:quickload '(:cl-debug-print :fiveam))
                 (shadow :run)
                 (use-package :fiveam)))
#+swank (cl-syntax:use-syntax cl-debug-print:debug-print-syntax)

;; BEGIN_INSERTED_CONTENTS
(defmacro nlet (name args &body body)
  (labels ((ensure-list (x) (if (listp x) x (list x))))
    (let ((args (mapcar #'ensure-list args)))
      `(labels ((,name ,(mapcar #'car args) ,@body))
         (,name ,@(mapcar #'cadr args))))))

(declaim (ftype (function * (values simple-bit-vector &optional)) make-prime-table))
(defun make-prime-table (size)
  "Erzeugt die Primzahlentabelle 0 zu SIZE-1."
  (declare (optimize (speed 3) (safety 1)))
  (let ((dict (make-array size :element-type 'bit :initial-element 1)))
    (setf (sbit dict 0) 0 (sbit dict 1) 0)
    (loop for even-num from 4 below size by 2
          do (setf (sbit dict even-num) 0))
    (loop for p from 3 to (ceiling (sqrt size)) by 2
          when (= 1 (sbit dict p))
          do (loop for composite from (+ p p) below size by p
                   until (>= composite size)
                   do (setf (sbit dict composite) 0)))
    dict))

;; (with-memoizing (:hash-table :test #'equal :key #'cons)
;;   (defun ...))
;; (with-memoizing (:array '(10 10 10) :initial-element -1 :element-type 'fixnum)
;;   (defun ...))
(defmacro with-memoizing (cache-attribs def-form)
  (let* ((cache-attribs (if (atom cache-attribs) (list cache-attribs) cache-attribs))
         (cache-type (first cache-attribs))
         (dimensions (when (eql cache-type :array) (second cache-attribs)))
         (rank (length dimensions))
         (rest-attribs (ecase cache-type
                         (:hash-table (cdr cache-attribs))
                         (:array (cddr cache-attribs))))
         (key (prog1 (getf rest-attribs :key) (remf rest-attribs :key)))
         (cache-form (case cache-type
                       (:hash-table `(make-hash-table ,@rest-attribs))
                       (:array `(make-array ,dimensions ,@rest-attribs))))
         (initial-element (when (eql cache-type :array)
                            (assert (member :initial-element rest-attribs))
                            (getf rest-attribs :initial-element))))
    (let ((cache (gensym))
          (value (gensym))
	  (present-p (gensym))
          (name-alias (gensym))
	  (args-lst (gensym))
          (indices (loop repeat rank collect (gensym))))
      (labels ((make-cache-check-form (cache-type args)
                 (case cache-type
                   (:hash-table
                    `(let ((,args-lst (funcall ,(or key #'list) ,@args)))
                       (multiple-value-bind (,value ,present-p)
                           (gethash ,args-lst ,cache)
                         (if ,present-p
                             ,value
                             (setf (gethash ,args-lst ,cache)
                                   (,name-alias ,@args))))))
                   (:array
                    (if key
                        `(multiple-value-bind ,indices
                             (funcall ,key ,@args)
                           (let ((,value (aref ,cache ,@indices)))
                             (if (eql ,initial-element ,value)
                                 (setf (aref ,cache ,@indices)
                                       (,name-alias ,@args))
                                 ,value)))
                        `(let ((,value (aref ,cache ,@args)))
                           (if (eql ,initial-element ,value)
                               (setf (aref ,cache ,@args)
                                     (,name-alias ,@args))
                               ,value))))))
               (make-reset-form (cache-type)
                 (case cache-type
                   (:hash-table `(setf ,cache (make-hash-table ,@rest-attribs)))
                   (:array `(prog1 nil
                              (fill (array-storage-vector ,cache) ,initial-element)))))
               (make-reset-name (name)
                 (intern (format nil "RESET-~A" (symbol-name name)))))
        (ecase (car def-form)
          ((defun)
           (destructuring-bind (_ name args &body body) def-form
             (declare (ignore _))
             `(let ((,cache ,cache-form))
                (defun ,(make-reset-name name) () ,(make-reset-form cache-type))
                (defun ,name ,args
                  (labels ((,name-alias ,args ,@body))
                    (declare (inline ,name-alias))
                    ,(make-cache-check-form cache-type args))))))
          ((nlet)
           (destructuring-bind (_ name bindings &body body) def-form
             (declare (ignore _))
             `(let ((,cache ,cache-form))
                (nlet ,name ,bindings
                  ,(let ((args (mapcar (lambda (x) (if (atom x) x (car x))) bindings)))
                     `(labels ((,name-alias ,args ,@body))
                        (declare (inline ,name-alias))
                        ,(make-cache-check-form cache-type args)))))))
          ((labels flet)
           (destructuring-bind (_ definitions &body labels-body) def-form
             (declare (ignore _))
             (destructuring-bind (name args &body body) (car definitions)
               `(let ((,cache ,cache-form))
                  (,(car def-form)
                   ((,(make-reset-name name) () ,(make-reset-form cache-type))
                    (,name ,args
                           (labels ((,name-alias ,args ,@body))
                             (declare (inline ,name-alias))
                             ,(make-cache-check-form cache-type args)))
                    ,@(cdr definitions))
                   (declare (ignorable #',(make-reset-name name)))
                   ,@labels-body))))))))))

(defmacro define-int-types (&rest bits)
  `(progn
     ,@(mapcar (lambda (b) `(deftype ,(intern (format nil "UINT~A" b)) () '(unsigned-byte ,b))) bits)
     ,@(mapcar (lambda (b) `(deftype ,(intern (format nil "INT~A" b)) () '(signed-byte ,b))) bits)))
(define-int-types 4 7 8 15 16 31 32 62 63 64)

(defmacro println (obj &optional (stream '*standard-output*))
  `(let ((*read-default-float-format* 'double-float))
     (prog1 (princ ,obj ,stream) (terpri ,stream))))

;; Hauptteil
(defconstant +magic+ #.(+ 7 (expt 10 9)))
(defun decompose (m)
  (declare #.OPT
           (uint32 m))
  (let* ((factor-sup (ceiling (sqrt m)))
         (prime-table (make-prime-table (1+ factor-sup))))
    (loop for i from 2 below (length prime-table)
          when (= 1 (sbit prime-table i))
          collect (nlet recurse ((count 0))
                    (declare (uint32 count))
                    (multiple-value-bind (quot rem) (floor m i)
                      (if (zerop rem)
                          (progn (setf m quot)
                                 (recurse (1+ count)))
                          count)))
          into factors
          finally (return
                    (let ((factors (delete 0 (the list factors))))
                      (if (= 1 m)
                          factors
                          (append factors (list 1))))))))

(with-memoizing (:array '(100001 32) :element-type 'fixnum :initial-element -1)
  (defun multiset-coefficient (n k)
    (declare #.OPT
             ((integer 1 #.most-positive-fixnum) n)
             ((integer 0 #.most-positive-fixnum) k))
    (cond ((zerop k) 1)
          ((= n 1) 1)
          (t (mod (the uint63 (+ (multiset-coefficient (- n 1) k)
                                 (multiset-coefficient n (- k 1))))
                  +magic+)))))

(defun main ()
  (let* ((n (read))
         (m (read))
         (factors (decompose m)))
    (if (= m 1)
        (println 1)
        (println
         (reduce (lambda (x y) (mod (* x y) +magic+))
                 factors
                 :key (lambda (k) (multiset-coefficient n k)))))))

#-swank(main)