leetcode 统计理想数组的数目
给你两个整数 n n n 和 m a x V a l u e maxValue maxValue ,用于描述一个 理想数组 。
对于下标从 0 0 0 开始、长度为 n n n 的整数数组 a r r arr arr ,如果满足以下条件,则认为该数组是一个 理想数组 :
- 每个 a r r [ i ] arr[i] arr[i] 都是从 1 1 1 到 m a x V a l u e maxValue maxValue 范围内的一个值,其中 0 < = i < n 0 <= i < n 0<=i<n 。
- 每个 a r r [ i ] arr[i] arr[i] 都可以被 a r r [ i − 1 ] arr[i - 1] arr[i−1] 整除,其中 0 < i < n 0 < i < n 0<i<n 。
返回长度为 n n n 的 不同 理想数组的数目。由于答案可能很大,返回对 1 0 9 + 7 10^9 + 7 109+7 取余的结果。
思路
理想数组满足:数组里的每个数都在
[
1
,
m
a
x
V
l
a
u
e
]
[1,maxVlaue]
[1,maxVlaue],且每个数都是前一个数的倍数(倍数包括1)
首先考虑一个简化版本,当每个数都是前一个数的倍数,倍数不包括1,即数组严格递增。因为
m
a
x
V
a
l
u
e
≤
1
e
4
maxValue\leq 1e4
maxValue≤1e4,所以此时数组的长度最多为
14
14
14(
2
13
=
8192
2^{13}=8192
213=8192),所以可以使用动态规划,状态
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示以
i
i
i开头的,长度为
j
j
j的数组方案数。所以
f
[
i
]
[
j
]
=
s
u
m
(
f
[
i
∗
k
]
[
j
−
1
]
)
f[i][j]=sum(f[i*k][j-1])
f[i][j]=sum(f[i∗k][j−1]),其中
i
∗
k
≤
m
a
x
V
a
l
u
e
i*k \leq maxValue
i∗k≤maxValue,这层循环的时间复杂度为
1
+
1
/
2
+
1
/
3
+
.
.
.
+
1
/
n
=
l
n
(
n
)
+
C
1+1/2+1/3+...+1/n=ln(n)+C
1+1/2+1/3+...+1/n=ln(n)+C。所以整体的时间复杂度为
O
(
14
n
l
n
(
n
)
)
O(14nln(n))
O(14nln(n))。此时求出了严格递增的理想数组个数。但是理想数组中存在前后元素倍数为1的情况,此时使用组合数学的知识,对
f
[
i
]
[
j
]
f[i][j]
f[i][j],可以使用隔板法将长度为
n
n
n的数组隔成
j
j
j段,那么共有
f
[
i
]
[
j
]
∗
C
n
−
1
j
−
1
f[i][j]*C_{n-1}^{j-1}
f[i][j]∗Cn−1j−1,最后将每个状态累加即可。
对于
C
n
m
C_n^m
Cnm,有
C
n
m
=
C
n
−
1
m
−
1
+
C
n
−
1
m
C_n^m=C_{n-1}^{m-1}+C_{n-1}^m
Cnm=Cn−1m−1+Cn−1m
代码
class Solution {
public int idealArrays(int n, int maxValue) {
int MOD = (int)(1e9 + 7);
int[][] cnt = new int[maxValue + 1][15];
for(int i = 1; i <= maxValue; i++) {
cnt[i][1] = 1;
}
for(int i = 2; i < 15; i++) {
for(int j = 1; j <= maxValue; j++) {
for(int k = 2; k * j <= maxValue; k++) {
cnt[j][i] = (cnt[j][i] + cnt[j * k][i-1]) % MOD;
}
}
}
int[][] C = new int[n][15];
for(int i = 0; i < n; i++) {
C[i][0] = 1;
}
for(int i = 1; i < n; i++) {
for(int j = 1; j < 15; j++) {
C[i][j] = (C[i-1][j-1] + C[i-1][j]) % MOD;
}
}
int res = 0;
for(int i = 1; i <= maxValue; i++) {
for(int j = 1; j < 15; j++) {
int x = (int)((long)cnt[i][j] * C[n-1][j-1] % MOD);
res = (res + x) % MOD;
}
}
return res;
}
}