题目链接
Leetcode.2338 统计理想数组的数目 Rating : 2615
题目描述
给你两个整数 n n n 和 m a x V a l u e maxValue maxValue ,用于描述一个 理想数组 。
对于下标从 0 开始、长度为 n n n 的整数数组 a r r arr arr ,如果满足以下条件,则认为该数组是一个 理想数组 :
- 每个 a r r [ i ] arr[i] arr[i] 都是从 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 的 不同 理想数组的数目。由于答案可能很大,返回对 1 0 9 + 7 10^9 + 7 109+7 取余的结果。
示例 1:
输入:n = 2, maxValue = 5
输出:10
解释:存在以下理想数组:
- 以 1 开头的数组(5 个):[1,1]、[1,2]、[1,3]、[1,4]、[1,5]
- 以 2 开头的数组(2 个):[2,2]、[2,4]
- 以 3 开头的数组(1 个):[3,3]
- 以 4 开头的数组(1 个):[4,4]
- 以 5 开头的数组(1 个):[5,5] 共计 5 + 2 + 1 + 1 + 1 = 10 个不同理想数组。
示例 2:
输入:n = 5, maxValue = 3
输出:11
解释:存在以下理想数组:
- 以 1 开头的数组(9 个):
- 不含其他不同值(1 个):[1,1,1,1,1]
- 含一个不同值 2(4 个):[1,1,1,1,2], [1,1,1,2,2], [1,1,2,2,2], [1,2,2,2,2]
- 含一个不同值 3(4 个):[1,1,1,1,3], [1,1,1,3,3], [1,1,3,3,3], [1,3,3,3,3]
- 以 2 开头的数组(1 个):[2,2,2,2,2]
- 以 3 开头的数组(1 个):[3,3,3,3,3] 共计 9 + 1 + 1 = 11 个不同理想数组。
提示:
- 2 < = n < = 1 0 4 2 <= n <= 10^4 2<=n<=104
- 1 < = m a x V a l u e < = 1 0 4 1 <= maxValue <= 10^4 1<=maxValue<=104
解法:质因数分解 & 组合数学
由于 理想数组 a r r [ i − 1 ] arr[i-1] arr[i−1] 能整除 a r r [ i ] arr[i] arr[i],如果 a r r [ i ] = 2 × a r r [ i − 1 ] arr[i] = 2 \times arr[i-1] arr[i]=2×arr[i−1] ,即每次扩大一倍的话。
由于 a r r [ i ] ≤ 1 0 4 arr[i] \leq 10^4 arr[i]≤104,所以 理想数组 的最大扩大次数为 ⌈ l o g 2 10000 ⌉ = 13 \lceil log_2^{10000} \rceil = 13 ⌈log210000⌉=13。
我们可以考虑 理想数组 的第一项都是从 1 1 1 开始的。
假设 n = 5 n = 5 n=5 且 最后一个元素是 8 8 8,所谓的 理想数组 实际上就是把 8 8 8 的质因子,分摊到 这 5 5 5 个位置上: [ 1 , 1 , 1 , 1 , 1 ] [1,1,1,1,1] [1,1,1,1,1]。
- [ × 2 , _ , _ , × 2 , × 2 ] [\times 2,\_,\_,\times 2,\times 2] [×2,_,_,×2,×2],等价于 [ 2 , 2 , 2 , 4 , 8 ] [2,2,2,4,8] [2,2,2,4,8];
- [ × 2 , × 2 , _ , _ , × 2 ] [\times 2,\times 2,\_,\_,\times 2] [×2,×2,_,_,×2],等价于 [ 2 , 4 , 4 , 4 , 8 ] [2,4,4,4,8] [2,4,4,4,8];
- [ × 4 , × 2 , _ , _ , _ ] [\times 4,\times 2,\_,\_,\_] [×4,×2,_,_,_],等价于 [ 4 , 8 , 8 , 8 , 8 ] [4,8,8,8,8] [4,8,8,8,8];
- [ × 8 , _ , _ , _ , _ ] [\times 8,\_,\_,\_,\_] [×8,_,_,_,_],等价于 [ 8 , 8 , 8 , 8 , 8 ] [8,8,8,8,8] [8,8,8,8,8];
- …
我们要做的就是求出所有的这些方案。
因为 理想数组 的最后一项元素 x x x 可以被分解为:
x = p 1 c 1 × p 2 c 2 × p 3 c 3 × . . . × p k c k x = p_1^{c_1} \times p_2^{c_2} \times p_3^{c_3} \times...\times p_k^{c_k} x=p1c1×p2c2×p3c3×...×pkck
我们就是要把 c i c_i ci 个 质因子 p i p_i pi 放到 n n n 个位置中。问题转化为: n n n 个盒子放小球的问题,允许存在空盒子。
假设有 n n n 个盒子, k k k 个小球。
n n n 个盒子,就有 n − 1 n - 1 n−1 个 隔板,加上 k k k 个小球,共有 n − k + 1 n - k + 1 n−k+1 个位置。用 n − 1 n - 1 n−1 个位置放隔板;用 k k k 个位置放小球;
所以总的方案数为: C n − k + 1 n − 1 C_{n-k + 1}^{n-1} Cn−k+1n−1 或者 C n − k + 1 k C_{n-k + 1}^{k} Cn−k+1k 。
因为一个元素 x x x 可能有 不同的 若干个质因子,我们采用乘法原理计算。
最终的答案就是 从 i ( 1 ≤ i ≤ m a x V a l u e ) i (1 \leq i \leq maxValue ) i(1≤i≤maxValue) 开始,枚举每一个 i i i 的质因数 放到 n n n 个位置中的方案数之和。
时间复杂度:
C++代码:
const int MOD = 1e9 + 7, MX = 1e4 + 1, K = 13; // 因为最多扩大 13 次
// cnt[x] 为 x 分解质因数后,每个质因数的个数列表
//比如 x = 12,cnt[x] = {2,1},因为质因子 2 有两个,质因子 3 有一个
vector<int> cnt[MX];
int c[MX + K][K + 1]; // 组合数
//预处理出 2~10000 的质因数列表 以及 组合数
int init = []() {
//求 2~10000 的质因数列表
for (int i = 2; i < MX; ++i) {
int x = i;
for (int p = 2; p * p <= x; ++p) {
if (x % p == 0) {
int k = 0;
while(x % p == 0){
k++;
x /= p;
}
cnt[i].push_back(k);
}
}
if (x > 1) cnt[i].push_back(1);
}
//求出 C(n -k + 1 , k) , C(n - k + 1,n - 1) 范围内的所有组合数
c[0][0] = 1;
for (int i = 1; i < MX + K; ++i) {
c[i][0] = 1;
for (int j = 1; j <= min(i, K); ++j)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
}
return 0;
}();
class Solution {
public:
int idealArrays(int n, int maxValue) {
long long ans = 0LL;
for (int x = 1; x <= maxValue; ++x) {
long long mul = 1LL;
//乘法原理 求x 的每一种质因子 放入n个位置中的方案数
for (int k: cnt[x]) mul = mul * c[n + k - 1][k] % MOD;
ans += mul;
}
return ans % MOD;
}
};