2025-04-22 Daily Challenge
Today I have done leetcode's April LeetCoding Challenge with cpp
.
April LeetCoding Challenge 22
Description
Count the Number of Ideal Arrays
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
Solution
firstly it's natural to think that we could use dp[len][lastDigit]
to do a dynamic programming, then you would find there is no need to store every state of len
, so we just have dp[lastDigit]
& dp[prevLastDigit]
.
then you would realize it's just like Matrix Exponentiation problem but here we need to calculate the matrix first.
take maxValue = 5 as an example, if we reach a state with [a, b, c, d, e]
, then next state will be [a, a + b, a + c, a + b + d, a + e]
. which we could accelerate the calculation by Matrix Exponentiation like we do in fibonacci problem. Though we need to calculate the matrix.
in this case, the original array is $[1, 1, 1, 1, 1]$, and the matrix would be $\begin{bmatrix}1 & 0 & 0 & 0 & 0\1 & 1 & 0 & 0 & 0\1 & 0 & 1 & 0 & 0\1 & 1 & 0 & 1 & 0\1 & 0 & 0 & 0 & 1\end{bmatrix}$. basically if $a$ is divisible by $b$, then $matrix[a][b]$ would be $1$.
ah fk, I got memory limit exceed...
using ll = long long;
vector<vector<ll>> unitMatrix(int sz) {
vector<vector<ll>> result(sz, vector<ll>(sz));
for(int i = 0; i < sz; ++i) result[i][i] = 1;
return result;
}
void multiply(
const vector<vector<ll>> &a,
const vector<vector<ll>> &b,
vector<vector<ll>> &result,
const int mod
) {
int rows = result.size();
int cols = result.front().size();
int aRows = b.size();
for(int i = 0; i < rows; ++i) {
for(int j = 0; j < cols; ++j) {
result[i][j] = 0;
for(int k = 0; k < aRows; ++k) {
result[i][j] += a[i][k] * b[k][j];
result[i][j] %= mod;
}
}
}
}
void qpow(
vector<vector<ll>> &base,
int exp,
vector<vector<ll>> &result,
const int mod
) {
vector<vector<ll>> temp(result);
while(exp) {
if(exp & 1) {
multiply(base, result, temp, mod);
swap(result, temp);
}
multiply(base, base, temp, mod);
swap(base, temp);
exp >>= 1;
}
}
class Solution {
const int MOD = 1e9 + 7;
public:
int idealArrays(int n, int maxValue) {
if(n == 1) return maxValue;
vector<vector<ll>> initial(1, vector<ll>(maxValue, 1));
// cout << initial << endl;
vector<vector<ll>> formula(maxValue, vector<ll>(maxValue));
for(int i = 1; i <= maxValue; ++i) {
for(int j = i; j <= maxValue; j += i) {
formula[j - 1][i - 1] = 1;
}
}
// cout << formula << endl;
vector<vector<ll>> temp = unitMatrix(maxValue);
// cout << temp<< endl;
qpow(formula, n - 1, temp, MOD);
// cout << temp << endl;
vector<vector<ll>> result(initial);
multiply(initial, temp, result, MOD);
// cout << result << endl;
int answer = 0;
for(int i = 0; i < maxValue; ++i) {
answer += result[0][i];
answer %= MOD;
}
return answer;
}
};
// Memory Limit Exceeded
// Your Input
// 3
// 10000
the real solution is really great though.
using ll = long long;
ll factorial[10001] = {};
inline ll qpow(ll base, ll exp, ll mod) {
ll result = 1;
while(exp) {
if(exp & 1) {
result *= base;
result %= mod;
}
base *= base;
base %= mod;
exp >>= 1;
}
return result;
}
inline ll fact(ll a, ll mod) {
if(a == 0) return 1;
if(factorial[a]) return factorial[a];
return factorial[a] = (a * fact(a - 1, mod)) % mod;
}
inline ll modInv(ll a, ll b, ll mod) {
return (((fact(a, mod) * qpow(fact(b, mod), mod - 2, mod)) % mod) * qpow(fact(a - b, mod), mod - 2, mod)) % mod;
}
class Solution {
const int MOD = 1e9 + 7;
public:
int idealArrays(int n, int maxValue) {
vector<vector<ll>> dp(maxValue + 1, vector<ll>(15));
for(int i = 1; i <= maxValue; ++i) {
dp[i][1] = 1;
for(int j = 2; j * i <= maxValue; ++j) {
for(int k = 1; k < min(n, 14); ++k) {
dp[i * j][k + 1] += dp[i][k];
}
}
}
ll answer = 0;
for(int i = 1; i <= maxValue; ++i) {
for(int j = 1; j <= min(n, 14); ++j) {
answer += modInv(n - 1, n - j, MOD) * dp[i][j];
answer %= MOD;
}
}
return answer;
}
};
// Accepted
// 47/47 cases passed (467 ms)
// Your runtime beats 5.17 % of cpp submissions
// Your memory usage beats 20.69 % of cpp submissions (31.4 MB)