Leetcode.1735 生成乘积数组的方案数

题目链接

Leetcode.1735 生成乘积数组的方案数 rating : 2500

题目描述

给你一个二维整数数组 q u e r i e s queries queries ,其中 q u e r i e s [ i ] = [ n i , k i ] queries[i] = [n_i, k_i] queries[i]=[ni,ki] 。第 i i i 个查询 q u e r i e s [ i ] queries[i] queries[i] 要求构造长度为 n i n_i ni 、每个元素都是正整数的数组,且满足所有元素的乘积为 k i k_i ki ,请你找出有多少种可行的方案。由于答案可能会很大,方案数需要对 1 0 9 + 7 10^9 + 7 109+7 取余 。

请你返回一个整数数组 a n s w e r answer answer,满足 a n s w e r . l e n g t h = = q u e r i e s . l e n g t h answer.length == queries.length answer.length==queries.length ,其中 a n s w e r [ i ] answer[i] answer[i] 是第 i i i 个查询的结果。

示例 1:
输入:queries = [[2,6],[5,1],[73,660]]
输出:[4,1,50734910]
解释:每个查询之间彼此独立。
[2,6]:总共有 4 种方案得到长度为 2 且乘积为 6 的数组:[1,6],[2,3],[3,2],[6,1]。
[5,1]:总共有 1 种方案得到长度为 5 且乘积为 1 的数组:[1,1,1,1,1]。
[73,660]:总共有 1050734917 种方案得到长度为 73 且乘积为 660 的数组。1050734917 对 109 + 7 取余得到 50734910 。
示例 2:
输入:queries = [[1,1],[2,2],[3,3],[4,4],[5,5]]
输出:[1,2,3,10,5]
提示:
  • 1 ≤ q u e r i e s . l e n g t h ≤ 1 0 4 1 \leq queries.length \leq 10^4 1≤queries.length≤104
  • 1 ≤ n i , k i ≤ 1 0 4 1 \leq n_i, k_i \leq 10^4 1≤ni,ki≤104

解法:组合数学 + 质因数分解

对于 [ n i , k i ] [n_i, k_i] [ni,ki] 就等价于 有 n i n_i ni 个相同的箱子,要把 k i k_i ki 的所有 质因子 放入到这 n i n_i ni 箱子中,有的箱子可以为空

例如 [ 2 , 6 ] [2, 6] [2,6],就是有 2 2 2 个箱子 [ ] [ ] [\ ] [\ ] [ ][ ], n = 2 × 3 n = 2 \times 3 n=2×3。一共有 4 4 4 种放法:

  • [ 2 ∗ 3 ] [ ] [2 * 3 ] [\ ] [2∗3][ ]
  • [ ] [ 2 ∗ 3 ] [\ ] [2 * 3] [ ][2∗3]
  • [ 2 ] [ 3 ] [2] [3] [2][3]
  • [ 3 ] [ 2 ] [3] [2] [3][2]

我们可以发现,对于不同的质因子都可以单独计算。假设这里把质因子 2 2 2 看作是小球 A A A,把质因子 3 3 3 看作是小球 B B B。

  • 把小球 A A A 放到两个箱子中,一共有两种放法: [ A ] [ ] , [ ] [ A ] [A] [\ ], [\ ] [A] [A][ ],[ ][A]
  • 把小球 B B B 放到两个箱子中,一共有两种放法: [ B ] [ ] , [ ] [ B ] [B] [\ ], [\ ] [B] [B][ ],[ ][B]

所以一共有 2 × 2 = 4 2 \times 2 = 4 2×2=4 种放法。

假设一共有 m m m 个箱子, n n n 个球,把 n n n 个球放进 m m m 个箱子,并且允许出现空箱子的放法有多少种。

等价于 一共有 n + m n + m n+m 个球,要把这 n + m n + m n+m 个球分割成 m m m 部分,也就是 C ( n + m − 1 , m − 1 ) = C ( n + m − 1 , n ) C(n + m - 1, m - 1) = C(n + m - 1, n) C(n+m−1,m−1)=C(n+m−1,n)。

例如:假设有 3 3 3 个小球,要放到 4 4 4 个盒子中。

等价于 有 3 + 4 3 + 4 3+4 个小球,再把小球分为 4 4 4 个部分的方案数量

3 + 4 3 +4 3+4 个小球,一共有 3 + 4 − 1 = 6 3 + 4 - 1 = 6 3+4−1=6 个位置,要把这 7 7 7 个小球分为 4 4 4 个部分,直接从 6 6 6 个隔板中选 4 4 4 个插入,即 C ( 6 , 4 ) C(6, 4) C(6,4);

推广到 n n n 个小球, m m m 个箱子就是 C ( n + m − 1 , m − 1 ) = C ( n + m − 1 , n ) C(n + m - 1, m - 1) = C(n + m - 1, n) C(n+m−1,m−1)=C(n+m−1,n)。

那么我们就可以处理出 k i k_i ki 的所有质因数,也就是求出所有 小球,最后计算方案即可。

时间复杂度: ( ( N + l o g K ) l o g K ) ((N + logK) logK) ((N+logK)logK)

C++代码:

cpp 复制代码
using LL = long long;
const int MOD = 1e9 + 7;
const int N = 1e4 + 15;
LL c[N][15];

auto _ = []()
{
    c[0][0] = 1;
    for(int i = 1;i < N;i++)
    {
        c[i][0] = 1;
        for(int j = 1;j < 15;j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
    }
    return 0;
}();

class Solution {
public:
    vector<int> waysToFillArray(vector<vector<int>>& queries) {
        vector<int> ans;

        for(auto q:queries)
        {
            int n = q[0], k = q[1];
            LL res = 1;
            auto x = k;

            for(int i = 2;i <= x / i;i++)
            {
                if(x % i == 0)
                {
                    int cnt = 0;
                    while(x % i == 0)
                    {
                        x /= i;
                        cnt++;
                    }

                    res = res * c[cnt + n - 1][cnt] % MOD;
                }
            }

            if(x > 1) res = res * n % MOD;
            ans.push_back(res);
        }

        return ans;
    }
};
相关推荐
Ryan_Adam11 天前
组合数学学习笔记
组合数学
summ1ts2 个月前
组合数求法汇总
c++·数学·算法·离散数学·组合数学
感觉画质不如…原神5 个月前
Leetcode.2709 最大公约数遍历
质因数分解·并查集
闻缺陷则喜何志丹6 个月前
【组合数学 隔板法 容斥原理】放球问题
c++·算法·组合数学·容斥原理·隔板法·放球问题·盒子
Espresso Macchiato1 年前
数学杂谈:不经过x轴下方的随机行走问题
组合数学·随机行走·递推算法·数学竞赛
闻缺陷则喜何志丹1 年前
C++二分查找算法的应用:长度递增组的最大数目
开发语言·c++·算法·二分查找·数论·数组·组合数学
Code920071 年前
Pinely Round 2 (Div. 1 + Div. 2) G. Swaps(组合计数)
组合数学·计数
xhchen20231 年前
第 358 场LeetCode周赛题解
数据结构·算法·leetcode·有序集合·单调栈·快速幂·质因数分解