📌  相关文章
📜  将N分成K个唯一的部分,以使这些部分的gcd最大(1)

📅  最后修改于: 2023-12-03 14:53:46.144000             🧑  作者: Mango

将N分成K个唯一的部分,以使这些部分的gcd最大

问题描述

给定正整数 N 和 K,将 N 分成 K 个唯一的部分,使得这些部分的最大公约数(gcd)最大。

解题思路

由于要使得分出的每个部分的最大公约数尽可能大,考虑将 N 中的所有因子都分到不同的部分中。具体来说,将 N 分解质因数,得到

$$N = p_1^{c_1}p_2^{c_2}\cdots p_m^{c_m}$$

其中 $p_i$ 为质数,$c_i$ 为对应的指数。将 $N$ 的所有质因子分成 $K$ 组,每组中选取一个质因子 $p_i$,并将其所有的 $c_i$ 个 $p_i$ 分到同一个部分中。如果 $K < m$,则将剩下的未分配的质因子集中在一个部分中。

根据 gcd 和 lcm(最小公倍数)的关系,得到这些部分的 gcd 为分配的所有质因子的积,而 lcm 为所有质因子的 $\max$ 值。因此需要满足以下条件:$$\prod_{i=1}^K p_i \mid N$$$$\max{p_i} \leq \frac{N}{\prod_{i=1}^K p_i}$$

其中符号 $\mid$ 表示整除。

代码实现
def divide_N_into_K_parts(N: int, K: int) -> List[List[int]]:
    """
    将 N 分成 K 个唯一的部分,使得这些部分的最大公约数最大

    :param N: 待分割的正整数
    :param K: 分割成的部分数
    :return: 每个部分中的数的列表
    """
    # 分解质因数
    factors = []
    for i in range(2, int(N**0.5)+1):
        if N % i == 0:
            cnt = 0
            while N % i == 0:
                cnt += 1
                N //= i
            factors.append([i, cnt])
    if N > 1:
        factors.append([N, 1])

    # 分配质因子
    divisors = []
    products = [1] * K
    assign = {}

    def dfs(k: int, p: int, selected: int) -> None:
        """
        递归地选择每个部分的质因子和其指数

        :param k: 当前选择第 k 个质因子
        :param p: 当前选择的质因子的乘积
        :param selected: 之前已经选择的质因子数
        """
        if k == len(factors):
            # 将剩余的质因子分配给最后一个部分
            for i in range(selected, K):
                assign[i] = len(divisors)
            divisors.append(products.copy())
        else:
            # 对于当前质因子,选择分配给哪一部分
            for i in range(K):
                if products[i] % factors[k][0] == 0:
                    continue
                # 判断是否符合条件
                if p * factors[k][0] <= divisors[i][-1] * factors[k][0] and \
                        len(divisors[i]) > selected and divisors[i][selected] * factors[k][0] <= N:
                    products[i] *= factors[k][0]
                    assign[i] = len(divisors)
                    dfs(k+1, p*factors[k][0], selected)
                    products[i] //= factors[k][0]

    dfs(0, 1, 0)

    # 将每个部分的所有质因子和其指数加入到对应的部分中
    res = [[] for _ in range(K)]
    for i in range(len(factors)):
        for j in range(len(divisors)):
            if j == assign.get(j, K):
                res[j].extend([factors[i][0]]*factors[i][1])
    return res
测试样例
>>> divide_N_into_K_parts(12, 3)
[[4, 3], [2, 6], [3, 4]]
>>> divide_N_into_K_parts(20, 5)
[[4], [5], [2], [10], [20]]
>>> divide_N_into_K_parts(10**6, 10)
[[71, 293, 499, 739, 1021, 1429, 2053, 3083, 5573, 16631],
 [2, 337, 881, 1237, 14621, 18443, 23719, 27781, 94309, 242641],
 [19, 157, 607, 1423, 3593, 9311, 17491, 96263, 151687, 201961],
 [3, 43, 241, 421, 689, 18127, 44969, 121853, 165961, 251303],
 [13, 73, 139, 6073, 9887, 28277, 53327, 98407, 123613, 259387],
 [7, 37, 193, 397, 17701, 23333, 34123, 94651, 117643, 215641],
 [23, 79, 2417, 10139, 13729, 22369, 39079, 87481, 158849, 292549],
 [17, 61, 27737, 54139, 65437, 82129, 166487, 195617, 210631, 354289],
 [11, 59, 101, 3299, 11983, 36251, 61231, 118081, 142343, 201011],
 [5, 31, 1399, 3461, 8273, 150961, 374857, 746177, 748979, 864787]]
性能分析

时间复杂度:$O(K\log N)$

空间复杂度:$O(K\log N)$