生成乘积数组的方案数
难度:
标签:
题目描述
代码结果
运行时间: 69 ms, 内存: 21.7 MB
/*
* 思路:
* 1. 和普通Java版本类似,但尽量使用Stream来进行操作。
* 2. 分解质因数,计算组合数,和普通解法相同。
* 3. 通过Stream简化代码的操作。
*/
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SolutionStream {
private static final int MOD = 1000000007;
public int[] waysToFillArray(int[][] queries) {
return Arrays.stream(queries)
.mapToInt(query -> countWays(query[0], query[1]))
.toArray();
}
private int countWays(int n, int k) {
Map<Integer, Integer> primeFactors = getPrimeFactors(k);
return primeFactors.values().stream()
.mapToLong(power -> combination(n + power - 1, power))
.reduce(1L, (a, b) -> a * b % MOD)
.intValue();
}
private Map<Integer, Integer> getPrimeFactors(int num) {
return IntStream.rangeClosed(2, (int) Math.sqrt(num))
.filter(i -> num % i == 0)
.collect(HashMap::new, (map, i) -> {
while (num % i == 0) {
map.put(i, map.getOrDefault(i, 0) + 1);
num /= i;
}
}, HashMap::putAll);
}
private long combination(int n, int k) {
return IntStream.range(0, k)
.mapToLong(i -> (long)(n - i) * modInverse(i + 1, MOD) % MOD)
.reduce(1L, (a, b) -> a * b % MOD);
}
private long modInverse(long a, int mod) {
return power(a, mod - 2, mod);
}
private long power(long a, int b, int mod) {
long res = 1;
while (b > 0) {
if ((b & 1) != 0) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
}
解释
方法:
首先,题解使用了埃拉托斯特尼筛法来找出10^4范围内的所有质数,并标记每个数的最小质因数。然后,对于每个1到10^4的数,使用最小质因数将其分解,记录其质因数的幂次形成一个元组,存储于字典d中。对于每个查询[ni, ki],基于ki的质因数分解(从字典d中获取),使用组合数学计算将k分解为n个因子的方法数。具体计算方式是使用多项式定理中的多重集合公式来处理每个质因子的分配,其中涉及到的组合数可以通过math.comb函数高效计算。结果对10^9+7取余确保结果在规定范围内。
时间复杂度:
O(m * f)
空间复杂度:
O(n + m)
代码细节讲解
🦆
在题解中提到使用埃拉托斯特尼筛法来找出10^4范围内的所有质数,这个范围是如何确定的?
▷🦆
在处理质因数分解的过程中,题解说明使用了collections.defaultdict(int)来计数,为什么选择这种数据结构,而不是使用普通的字典或其他数据结构?
▷🦆
为什么在计算组合数时选择使用math.comb函数,并且在计算过程中立即取余,这样做的优点是什么?
▷🦆
在计算组合数时,如果n或k的数值非常大,是否会影响math.comb函数的性能或结果的精度?
▷