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

68 阅读5分钟

题目解析:## 魔法甜点之和:小包的新挑战

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

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

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

测试样例

样例1:

输入:n = 3, m = 2, s = 6, like = [1, 2, 3]
输出:5

样例2:

输入:n = 3, m = 1, s = 1, like = [1, 1, 1]
输出:6

样例3:

输入:n = 5, m = 3, s = 24, like = [1, 2, 3, 4, 5]
输出:1

样例4:

输入:n = 4, m = 0, s = 10, like = [1, 3, 3, 3]
输出:1

样例5:

输入:n = 6, m = 1, s = 35, like = [5, 5, 5, 5, 5, 5]
输出:0

问题描述分析

从代码的结构来看,问题的核心是给定一个长度为 n 的数组 like,数组中的每个元素代表某种物品的“喜欢数量”。我们需要从中选择某些物品,且要满足一些条件。具体的条件和目标如下:

  1. 你可以选择最多 m 个物品。
  2. 你选择的物品喜欢的数量的总和不能超过 s
  3. 每个物品不仅可以选择其“喜欢的数量”值,还可以选择其“喜欢数量的阶乘值”。

代码分析

1. 魔法数组 magic 和阶乘预处理

pythonCopy Code
magic = [1] * 100

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

这里定义了一个长度为 100 的数组 magic,用于存储从 0!99! 的阶乘值。pre() 函数负责对这个数组进行初始化,预计算好阶乘值,避免在后续的计算中重复计算阶乘。

2. 动态规划的状态转移

pythonCopy Code
def solution(n, m, s, like):
    pre()
    f = defaultdict(int)  # 使用defaultdict来初始化map
    f[(0, 0)] = 1  # 初始状态

f 是一个字典,用于记录状态,键是一个元组 (a, b),表示当前选中了 a 个物品,并且这些物品的“喜欢数量的总和”是 b。值是该状态下的组合数量。初始状态 (0, 0) 代表没有选择任何物品时,组合数量为 1。

3. 动态规划的主循环

pythonCopy Code
for i in range(1, n + 1):
    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

对于每个物品 i,我们都要尝试两种选择:

  1. 加入物品的“喜欢数量” :当前的总和 b 加上物品 i 的 like[i-1](表示物品的喜欢数量),如果加上后不超过 s,就将该状态的组合数量 v 加到新的状态 (a, b + like[i-1])
  2. 加入物品的“喜欢数量的阶乘” :如果当前已选物品数 a + 1 不超过 m 且当前总和 b + magic[like[i-1]](物品的阶乘值)不超过 s,那么就将该状态的组合数量 v 加到新的状态 (a + 1, b + magic[like[i-1]])

注意,g 是一个备份的字典,避免在遍历过程中修改原始字典 f 导致数据丢失。

4. 计算结果

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

最后,遍历所有可能选择物品的数量 a(从 0 到 m),累加那些“喜欢数量的总和等于 s”的状态下的组合数,得到最终的结果。

5. 主函数和测试用例

pythonCopy Code
if __name__ == "__main__":
    #  You can add more test cases here
    print(solution(3, 2, 6, [1,2,3]) == 5 )
    print(solution(3, 1, 1, [1,1,1]) == 6 )

测试用例通过比较函数 solution 的返回值与预期值来验证程序的正确性。

总结

这段代码的核心思想是通过动态规划(DP)来解决一个多重选择的组合问题,其中每个物品有两种选择:选择其喜欢的数量或选择其喜欢数量的阶乘值。通过字典存储每个状态(物品数和喜欢数量和),并通过状态转移逐步更新所有可能的组合方式,最终统计出满足条件的组合数。

主要技巧:

  1. 动态规划:利用 f[(a, b)] 来记录状态,避免重复计算。
  2. 备份字典:使用 g = f.copy() 来避免在遍历过程中修改原始状态。
  3. 阶乘预处理:通过 magic 数组预先计算阶乘值,避免重复计算。

心得:

使用MarsCode AI编写代码让我体验到了编程的便利与高效。AI能够快速生成代码示例,帮助我理解不同编程概念。通过交互式的反馈,我能迅速调整思路,解决问题。同时,MarsCode AI提供的建议让我了解到更多最佳实践,提升了我的编码水平。这种工具不仅节省了时间,还激发了我的创造力,尤其是在处理复杂问题时,AI的支持显得尤为重要。总的来说,MarsCode AI是编程学习和实践中的得力助手。