66 魔法甜点之和:小包的新挑战 | 豆包MarsCode AI刷题

122 阅读3分钟

问题描述:

(难)小R不再追求甜点中最高的喜爱值,今天他想要的是甜点喜爱值之和正好匹配他的预期值 S。为了达到这个目标,他可以使用魔法棒来改变甜点的喜爱值,使其变为原来喜爱值的阶乘。每个甜点只能使用一次魔法棒,也可以完全不用。

下午茶小哥今天带来了 N 个甜点,每个甜点都有一个固定的喜爱值。小R有 M 个魔法棒,他可以选择任意甜点使用,但每个甜点只能使用一次魔法棒。他的目标是通过选择一些甜点,可能使用魔法棒,使得这些甜点的喜爱值之和恰好为 S。

请计算小R有多少种不同的方案满足他的要求。如果两种方案中,选择的甜点不同,或者使用魔法棒的甜点不同,则视为不同的方案。

思路解析:

  • 目标:计算有多少种不同的方案可以选择一些甜点(可能使用魔法棒改变其喜爱值),使得这些甜点的喜爱值之和恰好等于给定的值S。
  • 限制:每个甜点只能使用一次魔法棒,也可以完全不用。使用魔法棒后,甜点的喜爱值会变为原来喜爱值的阶乘。

解题步骤:

  1. 初始化魔法棒阶乘数组

    定义一个数组 magic,其中 magic[i] 表示 i! 的值。 通过循环计算每个整数的阶乘并存储在 magic 数组中。

  2. 初始化动态规划数组

    使用一个字典 f 来存储动态规划状态,其中 f[(a, b)] 表示使用了 a 个魔法棒且当前喜爱值之和为 b 的方案数量。 初始状态 f[(0, 0)] = 1,表示没有使用任何魔法棒且喜爱值之和为0时只有一种方案(即不选择任何甜点)。

  3. 遍历甜点并更新状态

    对于每一个甜点 like[i-1],我们需要考虑两种情况:

    使用魔法棒,直接加上这个甜点的喜爱值。

    使用魔法棒,将这个甜点的喜爱值变为它的阶乘。

    复制当前状态 f 到临时状态 g,以避免在更新状态时的覆盖问题。

    遍历 g 中的每一个状态 (a, b),分别计算不使用魔法棒和使用魔法棒后的新状态,并更新到 f 中。

  4. 统计结果

    遍历 f 中所有使用了 0 到 m 个魔法棒且喜爱值之和为 s 的状态,累加这些状态的方案数量。

代码示例:

def pre():
    for i in range(1,100):
         magic[i] = magic[i-1] *i


def solution(n, m, s, like):
    pre()
    f = defaultdict(int) #
    f[(0,0)] = 1 #初始状态
    for i in range (1,1+n):
        g = f.copy() #备份当前状态
        for (a, b), v in g.items():
            if b + like[i - 1] <= s:  # 加入"喜欢"的数量
                f[(a, b + like[i - 1])] += v
            if a + 1 <= m and b + magic[like[i - 1]] <= s:  # 加入"喜欢的阶乘"
                f[(a + 1, b + magic[like[i - 1]])] += v

    sum_ = 0
    for i in range(m + 1):
        sum_ += f[(i, s)]  # 累加满足条件的结果
    
    return sum_

个人思考:

max_val的选择:在precompute_factorials函数中,max_val应该足够大,以覆盖所有可能的喜爱值。在上面的代码中,我简单地使用了max(like),但根据题目的实际情况,可能需要一个更大的值。

性能考虑:如果甜点的数量n、魔法棒的数量m或期望的喜爱值之和s非常大,动态规划的状态空间可能会非常大,导致内存不足或计算时间过长。在这种情况下,可能需要考虑优化算法或使用其他方法。

代码健壮性:在实际应用中,应该添加一些错误检查和异常处理来确保代码的健壮性。例如,检查输入参数的有效性、处理可能的除零错误等。