魔法甜点之和 丨豆包MarsCode AI刷题

114 阅读3分钟

这个问题可以通过动态规划(DP)和组合计算来解决。下面是解决思路的详细步骤:

1. 问题分析

我们有 NNN 个甜点,每个甜点有一个固定的喜爱值,同时可以选择使用 MMM 个魔法棒来改变某些甜点的喜爱值为阶乘。目标是通过选择甜点,并可能使用魔法棒,使得这些甜点的喜爱值之和恰好为预期值 SSS。

2. 解题思路

这个问题可以看作一种变体的“背包问题”,但同时需要处理魔法棒的使用,使得状态空间增加。

3. 状态表示

定义一个三维数组 dp[i][j][k],其中:

  • i 表示考虑前 iii 个甜点。
  • j 表示当前所选甜点的总喜爱值。
  • k 表示已经使用的魔法棒数量。

dp[i][j][k] 表示选择前 iii 个甜点、使得喜爱值之和为 jjj 且使用了 kkk 个魔法棒的方案数。

4. 转移方程

对于第 iii 个甜点,有以下几种选择:

  1. 不选这个甜点,保持总喜爱值和魔法棒使用数不变。
  2. 选这个甜点,不使用魔法棒,喜爱值增加 like[i],魔法棒使用数不变。
  3. 选这个甜点,使用魔法棒,将喜爱值变为 like[i]!,魔法棒使用数加 1(前提是 k+1≤Mk+1 \leq Mk+1≤M)。

因此,状态转移可以描述为:

dp[i][j][k]=dp[i−1][j][k]+dp[i−1][j−like[i]][k]+dp[i−1][j−factorial(like[i])][k−1]dp[i][j][k] = dp[i-1][j][k] + dp[i-1][j - \text{like}[i]][k] + dp[i-1][j - \text{factorial}(\text{like}[i])][k-1]dp[i][j][k]=dp[i−1][j][k]+dp[i−1][j−like[i]][k]+dp[i−1][j−factorial(like[i])][k−1]

其中 factorial(like[i]) 表示 like[i] 的阶乘。

5. 边界条件

  • 初始化:dp[0][0][0] = 1,即不选任何甜点、总和为 0 的方案数为 1。
  • 若所求的 jjj 或 kkk 超过目标 SSS 或 MMM,对应的 dp 值为 0。

6. 最终答案

遍历 dp[N][S][*] 中所有 * <= M 的情况,将这些方案数累加得到最终答案 `import math

def factorial(n): """计算 n 的阶乘""" return math.factorial(n)

def solution(n, m, s, like): # 计算所有甜点喜爱值的阶乘(仅计算小于等于 s 的值) factorial_values = {x: factorial(x) for x in set(like) if factorial(x) <= s}

# 初始化 DP 表
dp = [[[0] * (m + 1) for _ in range(s + 1)] for _ in range(n + 1)]
dp[0][0][0] = 1  # 不选任何甜点且总和为 0 的情况

# 填充 DP 表
for i in range(1, n + 1):
    for j in range(s + 1):
        for k in range(m + 1):
            # 不选第 i 个甜点
            dp[i][j][k] += dp[i - 1][j][k]
            
            # 选第 i 个甜点但不使用魔法棒
            if j >= like[i - 1]:
                dp[i][j][k] += dp[i - 1][j - like[i - 1]][k]

            # 选第 i 个甜点并使用魔法棒
            if k > 0 and like[i - 1] in factorial_values:
                fact_value = factorial_values[like[i - 1]]
                if j >= fact_value:
                    dp[i][j][k] += dp[i - 1][j - fact_value][k - 1]

# 统计结果
result = sum(dp[n][s][k] for k in range(m + 1))
return result

测试样例

print(solution(3, 2, 6, [1, 2, 3])) # 输出: 5 print(solution(3, 1, 1, [1, 1, 1])) # 输出: 6 print(solution(5, 3, 24, [1, 2, 3, 4, 5])) # 输出: 1 print(solution(4, 0, 10, [1, 3, 3, 3])) # 输出: 1 print(solution(6, 1, 35, [5, 5, 5, 5, 5, 5])) # 输出: 0 `

  • solution 函数接收参数 nnn, mmm, sss, 和甜点的喜爱值列表 like

  • 通过 factorial_values 预计算每个甜点喜爱值的阶乘(在合理范围内)。

  • 使用三重循环更新 DP 表 dp

  • 最后,将 dp[n][s][*] 中使用不同魔法棒数量(不超过 mmm)的方案数累加,得到最终答案。