You are given two integers n
and maxValue
, which are used to describe an ideal array.
A 0-indexed integer array arr
of length n
is considered ideal if the following conditions hold:
- Every
arr[i]
is a value from1
tomaxValue
, for0 <= i < n
. - Every
arr[i]
is divisible byarr[i - 1]
, for0 < i < n
.
Return the number of distinct ideal arrays of length n
. Since the answer may be very large, return it modulo 109 + 7
.
Example 1:
Input: n = 2, maxValue = 5 Output: 10 Explanation: The following are the possible ideal arrays: - Arrays starting with the value 1 (5 arrays): [1,1], [1,2], [1,3], [1,4], [1,5] - Arrays starting with the value 2 (2 arrays): [2,2], [2,4] - Arrays starting with the value 3 (1 array): [3,3] - Arrays starting with the value 4 (1 array): [4,4] - Arrays starting with the value 5 (1 array): [5,5] There are a total of 5 + 2 + 1 + 1 + 1 = 10 distinct ideal arrays.
Example 2:
Input: n = 5, maxValue = 3 Output: 11 Explanation: The following are the possible ideal arrays: - Arrays starting with the value 1 (9 arrays): - With no other distinct values (1 array): [1,1,1,1,1] - With 2nd distinct value 2 (4 arrays): [1,1,1,1,2], [1,1,1,2,2], [1,1,2,2,2], [1,2,2,2,2] - With 2nd distinct value 3 (4 arrays): [1,1,1,1,3], [1,1,1,3,3], [1,1,3,3,3], [1,3,3,3,3] - Arrays starting with the value 2 (1 array): [2,2,2,2,2] - Arrays starting with the value 3 (1 array): [3,3,3,3,3] There are a total of 9 + 1 + 1 = 11 distinct ideal arrays.
Constraints:
2 <= n <= 104
1 <= maxValue <= 104
Approach 01:
-
C++
-
Python
#include <vector> using namespace std; class Solution { public: int idealArrays(int arrayLength, int maxValue) { const int maxSequenceLength = min(14, arrayLength); const vector<vector<int>> factorList = getFactors(maxValue); vector<vector<long>> dp(maxSequenceLength + 1, vector<long>(maxValue + 1)); vector<vector<long>> combinationMemo(arrayLength, vector<long>(maxSequenceLength, -1)); long totalCount = 0; for (int value = 1; value <= maxValue; ++value){ dp[1][value] = 1; } for (int length = 2; length <= maxSequenceLength; ++length){ for (int value = 1; value <= maxValue; ++value){ for (const int factor : factorList[value]) { dp[length][value] += dp[length - 1][factor]; dp[length][value] %= kMod; } } } for (int length = 1; length <= maxSequenceLength; ++length) for (int value = 1; value <= maxValue; ++value) { dp[length][0] += dp[length][value]; dp[length][0] %= kMod; } for (int length = 1; length <= maxSequenceLength; ++length) { totalCount += dp[length][0] * computeCombination(arrayLength - 1, length - 1, combinationMemo); totalCount %= kMod; } return totalCount; } private: static constexpr int kMod = 1'000'000'007; vector<vector<int>> getFactors(int maxValue) { vector<vector<int>> factorList(maxValue + 1); for (int divisor = 1; divisor <= maxValue; ++divisor){ for (int multiple = divisor * 2; multiple <= maxValue; multiple += divisor){ factorList[multiple].push_back(divisor); } } return factorList; } long computeCombination(int n, int k, vector<vector<long>>& memo) { if (k == 0 || n == k){ return 1; } if (memo[n][k] != -1){ return memo[n][k]; } return memo[n][k] = (computeCombination(n - 1, k, memo) + computeCombination(n - 1, k - 1, memo)) % kMod; } };
from typing import List class Solution: MOD = 10**9 + 7 def idealArrays(self, arrayLength: int, maxValue: int) -> int: maxSequenceLength = min(14, arrayLength) factorList = self.getFactors(maxValue) dp = [[0] * (maxValue + 1) for _ in range(maxSequenceLength + 1)] combinationMemo = [[-1] * maxSequenceLength for _ in range(arrayLength)] totalCount = 0 for value in range(1, maxValue + 1): dp[1][value] = 1 for length in range(2, maxSequenceLength + 1): for value in range(1, maxValue + 1): for factor in factorList[value]: dp[length][value] += dp[length - 1][factor] dp[length][value] %= self.MOD for length in range(1, maxSequenceLength + 1): dp[length][0] = sum(dp[length][1:]) % self.MOD for length in range(1, maxSequenceLength + 1): totalCount += dp[length][0] * self.computeCombination(arrayLength - 1, length - 1, combinationMemo) totalCount %= self.MOD return totalCount def getFactors(self, maxValue: int) -> List[List[int]]: factorList = [[] for _ in range(maxValue + 1)] for divisor in range(1, maxValue + 1): for multiple in range(divisor * 2, maxValue + 1, divisor): factorList[multiple].append(divisor) return factorList def computeCombination(self, n: int, k: int, memo: List[List[int]]) -> int: if k == 0 or n == k: return 1 if memo[n][k] != -1: return memo[n][k] memo[n][k] = (self.computeCombination(n - 1, k, memo) + self.computeCombination(n - 1, k - 1, memo)) % self.MOD return memo[n][k]
Time Complexity:
- Factor List Generation:
For every number up to
maxValue
, we store its divisors → \( O(m \log m) \), where \( m = \text{maxValue} \) - DP Table Filling:
The DP table has at most 14 rows (sequence lengths) and \( m \) columns. For each cell, we sum over its factors → \( O(14 \cdot m \log m) \)
- Combination Computation:
Each combination is computed recursively and memoized. Total number of unique calls is \( O(n \cdot 14) \), where \( n = \text{arrayLength} \)
- Total Time Complexity:
\( O(m \log m + n \cdot 14 + 14 \cdot m \log m) = O(m \log m + n) \)
Space Complexity:
- DP Table:
We use a 2D table of size \( 15 \times (m + 1) \) → \( O(m) \)
- Factor List:
Stores divisors for each number up to \( m \) → \( O(m \log m) \)
- Combination Memoization Table:
Stores values for combinations up to \( n \times 14 \) → \( O(n) \)
- Total Space Complexity:
\( O(m \log m + n) \)