题目详解:魔法甜点之和:小包的新挑战
问题理解
本题的核心目标是找到一种方案,使得通过选择一些甜点并可能使用魔法棒(将甜点的喜爱值变为其阶乘),使得这些甜点的喜爱值之和恰好等于给定的预期值 S。每个甜点只能使用一次魔法棒,也可以完全不用。我们需要计算出满足条件的不同方案的数量。
数据结构选择
为了高效地解决这个问题,我们可以使用动态规划(Dynamic Programming, DP)来存储中间状态。具体来说,我们可以使用一个字典 f 来记录当前的状态,其中键是一个元组 (a, b),表示已经使用了 a 个魔法棒,当前喜爱值之和为 b 的方案数。
算法步骤
-
预处理阶乘值:
- 由于我们需要计算喜爱值的阶乘,因此可以预先计算出所有可能的阶乘值,并存储在一个数组
magic中。
- 由于我们需要计算喜爱值的阶乘,因此可以预先计算出所有可能的阶乘值,并存储在一个数组
-
初始化状态:
- 初始状态
f[(0, 0)]表示没有使用任何魔法棒,喜爱值之和为 0 的方案数为 1。
- 初始状态
-
动态规划更新状态:
- 对于每个甜点,我们有两个选择:
- 不使用魔法棒,直接将甜点的喜爱值加入当前的喜爱值之和。
- 使用魔法棒,将甜点的喜爱值变为其阶乘,并加入当前的喜爱值之和。
- 我们需要遍历所有甜点,并更新状态
f。
- 对于每个甜点,我们有两个选择:
-
统计结果:
- 最终,我们需要统计所有满足条件的方案数,即喜爱值之和为
S的所有状态。
- 最终,我们需要统计所有满足条件的方案数,即喜爱值之和为
代码详解
from collections import defaultdict
# 计算阶乘的魔法数组
magic = [1] * 100
def pre():
for i in range(1, 100):
magic[i] = magic[i - 1] * i
def solution(n, m, s, like):
pre()
f = defaultdict(int) # 使用defaultdict来初始化map
f[(0, 0)] = 1 # 初始状态
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
sum_ = 0
for i in range(m + 1):
sum_ += f[(i, s)] # 累加满足条件的结果
return sum_
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 )
-
预处理阶乘值:
magic数组用于存储从 1 到 99 的阶乘值。pre()函数用于预先计算这些阶乘值。
-
初始化状态:
f[(0, 0)] = 1表示初始状态下没有使用任何魔法棒,喜爱值之和为 0 的方案数为 1。
-
动态规划更新状态:
- 对于每个甜点
i,我们遍历当前的所有状态(a, b),并更新两种可能的状态:- 不使用魔法棒,直接将甜点的喜爱值加入当前的喜爱值之和。
- 使用魔法棒,将甜点的喜爱值变为其阶乘,并加入当前的喜爱值之和。
- 对于每个甜点
-
统计结果:
- 最终,我们遍历所有可能的魔法棒使用次数
i,累加满足条件的状态f[(i, s)],得到最终的方案数。
- 最终,我们遍历所有可能的魔法棒使用次数
测试样例分析
-
样例1:
- 输入:
n = 3, m = 2, s = 6, like = [1, 2, 3] - 输出:
5 - 解释:有 5 种不同的方案使得喜爱值之和为 6。
- 输入:
-
样例2:
- 输入:
n = 3, m = 1, s = 1, like = [1, 1, 1] - 输出:
6 - 解释:有 6 种不同的方案使得喜爱值之和为 1。
- 输入:
-
样例3:
- 输入:
n = 5, m = 3, s = 24, like = [1, 2, 3, 4, 5] - 输出:
1 - 解释:只有一种方案使得喜爱值之和为 24。
- 输入:
-
样例4:
- 输入:
n = 4, m = 0, s = 10, like = [1, 3, 3, 3] - 输出:
1 - 解释:只有一种方案使得喜爱值之和为 10。
- 输入:
-
样例5:
- 输入:
n = 6, m = 1, s = 35, like = [5, 5, 5, 5, 5, 5] - 输出:
0 - 解释:没有方案使得喜爱值之和为 35。
- 输入:
总结
本题通过动态规划的方法,有效地解决了在有限魔法棒使用次数下,选择甜点并可能使用魔法棒,使得喜爱值之和恰好等于预期值的问题。动态规划的状态转移方程清晰地描述了每一步的选择,并且通过预处理阶乘值,减少了重复计算,提高了算法的效率。