{x}
blog image

Count Ways to Make Array With Product

You are given a 2D integer array, queries. For each queries[i], where queries[i] = [ni, ki], find the number of different ways you can place positive integers into an array of size ni such that the product of the integers is ki. As the number of ways may be too large, the answer to the ith query is the number of ways modulo 109 + 7.

Return an integer array answer where answer.length == queries.length, and answer[i] is the answer to the ith query.

 

Example 1:

Input: queries = [[2,6],[5,1],[73,660]]
Output: [4,1,50734910]
Explanation: Each query is independent.
[2,6]: There are 4 ways to fill an array of size 2 that multiply to 6: [1,6], [2,3], [3,2], [6,1].
[5,1]: There is 1 way to fill an array of size 5 that multiply to 1: [1,1,1,1,1].
[73,660]: There are 1050734917 ways to fill an array of size 73 that multiply to 660. 1050734917 modulo 109 + 7 = 50734910.

Example 2:

Input: queries = [[1,1],[2,2],[3,3],[4,4],[5,5]]
Output: [1,2,3,10,5]

 

Constraints:

  • 1 <= queries.length <= 104
  • 1 <= ni, ki <= 104

Solution: Prime Factorization and Combinatorics

This problem can be efficiently solved using prime factorization and combinatorial mathematics. The core idea is to break down the problem into smaller, manageable parts.

1. Prime Factorization:

The first step is to find the prime factorization of k for each query [n, k]. This means expressing k as a product of its prime factors raised to certain powers. For example, the prime factorization of 660 is 2² * 3 * 5 * 11.

2. Combinatorial Approach:

Once we have the prime factorization, we treat each prime factor independently. Let's consider a single prime factor pᵢ with exponent xᵢ. We need to distribute xᵢ copies of pᵢ among n positions in the array. This is a classic stars and bars combinatorics problem. The number of ways to do this is given by the combination formula:

C(xᵢ + n - 1, n - 1) = C(xᵢ + n - 1, xᵢ)

where C(a, b) denotes "a choose b", the number of ways to choose b items from a set of a items.

3. Combining Results:

Since each prime factor is independent, we multiply the number of ways to distribute each prime factor to get the total number of ways to form the array. The final result is the product of all the combinations calculated for each prime factor, modulo 10⁹ + 7 (to prevent integer overflow).

4. Optimization:

To make the solution efficient, pre-computation is crucial. We pre-compute factorials and their modular inverses to quickly calculate combinations. Pre-computing prime factorizations for all numbers up to a certain limit also speeds up the process.

Time and Space Complexity Analysis:

  • Time Complexity: The dominant factor in the time complexity is the pre-computation of factorials and their modular inverses, which takes O(N) time, where N is the maximum value of k. The prime factorization of each k takes at most O(√k) time, and the combination calculation is O(1) due to pre-computation. Therefore, the overall time complexity is O(N + Q * √k_max), where Q is the number of queries and k_max is the maximum value of k in the queries. In practice, O(N) dominates for sufficiently large N.

  • Space Complexity: The space complexity is primarily determined by the pre-computed factorials, modular inverses, and the prime factorization data structure. This results in O(N) space complexity.

Code Implementation (Python):

import sys
from collections import defaultdict
 
MOD = 10**9 + 7
MAX_K = 10001  # Adjust as needed
 
# Pre-compute factorials and modular inverses
fact = [1] * MAX_K
inv_fact = [1] * MAX_K
for i in range(2, MAX_K):
    fact[i] = (fact[i - 1] * i) % MOD
    inv_fact[i] = pow(fact[i], MOD - 2, MOD)
 
def combinations(n, k):
    if k < 0 or k > n:
        return 0
    return (fact[n] * inv_fact[k] * inv_fact[n - k]) % MOD
 
def prime_factorization(n):
    factors = defaultdict(int)
    i = 2
    while i * i <= n:
        while n % i == 0:
            factors[i] += 1
            n //= i
        i += 1
    if n > 1:
        factors[n] += 1
    return factors
 
def waysToFillArray(queries):
    result = []
    for n, k in queries:
        factors = prime_factorization(k)
        ways = 1
        for prime, exponent in factors.items():
            ways = (ways * combinations(exponent + n - 1, n - 1)) % MOD
        result.append(ways)
    return result
 
queries = [[2, 6], [5, 1], [73, 660]]
print(waysToFillArray(queries))  # Output: [4, 1, 50734910]
 

This Python code demonstrates the solution with pre-computation for efficiency. Similar implementations can be done in Java, C++, or Go, with appropriate data structure choices for efficient prime factorization and combination calculations. The pre-computation step significantly improves performance, especially for a large number of queries or large values of k.