题目描述
给定N个甜点,每个甜点有一个固定的喜爱值。小R有M个魔法棒,可以选择任意甜点使用(每个甜点只能使用一次),使其喜爱值变为原来喜爱值的阶乘。小R的目标是选择一些甜点,可能使用魔法棒,使得这些甜点的喜爱值之和恰好为S。计算满足条件的方案数。
思路分析
这个问题可以通过动态规划(Dynamic Programming, DP)来解决。
动态规划的核心思想是将复杂问题分解成小的、易于解决的子问题,并找到这些子问题之间的递推关系。每个子问题只解决一次,并将其解保存起来,如果再次遇到相同的子问题,只是简单地查表取出已计算的结果。
初始化
dp[0][0] = 1:不使用魔法棒且总喜爱值为0的方案只有一种(即不选择任何甜点)。
其他 dp[i][j] 初始化为0。
定义状态
我们使用一个二维数组dp[i][j]来表示使用i个魔法棒,使得甜点的喜爱值之和为j的方案数。
状态转移方程 对于每个甜点,我们有两种选择:
- 不使用魔法棒,直接使用甜点的喜爱值;
- 使用魔法棒,将甜点的喜爱值变为其阶乘。
我们从后向前遍历 i 和 j,以避免重复使用同一个甜点(因为数组是覆盖更新的)。
因此,对于每个甜点,我们可以更新dp数组如下:
- 如果不使用魔法棒,那么
dp[i][j + like[k]] += dp[i][j],表示使用i个魔法棒,总喜爱值为j + like[k]的方案数等于使用i个魔法棒,总喜爱值为j的方案数加上当前的方案数。 - 如果使用魔法棒,那么
dp[i+1][j + factor] += dp[i][j],表示使用i+1个魔法棒,总喜爱值为j + factor的方案数等于使用i个魔法棒,总喜爱值为j的方案数加上当前的方案数。
边界条件:我们需要确保在更新dp数组时,i和j的值都在合法范围内,即i不能超过魔法棒的总数m,j不能超过预期值s。
计算结果
最后,我们遍历dp数组,将所有dp[i][s]的值相加,即可得到总方案数。
图解
假设输入为 n = 3, m = 2, s = 6, like = [1, 2, 3]:
- 初始化 DP 数组:
-
处理第一个甜点(喜爱值1) :
- 不使用魔法棒:
dp[i][j+1] += dp[i][j] - 使用魔法棒:
dp[i+1][j+1] += dp[i][j](因为factorial(1) = 1)
- 不使用魔法棒:
-
处理第二个甜点(喜爱值2) :
- 不使用魔法棒:
dp[i][j+2] += dp[i][j] - 使用魔法棒:
dp[i+1][j+2] += dp[i][j](因为factorial(2) = 2)
- 不使用魔法棒:
-
处理第三个甜点(喜爱值3) :
- 不使用魔法棒:
dp[i][j+3] += dp[i][j] - 使用魔法棒:
dp[i+1][j+6] += dp[i][j](因为factorial(3) = 6)
- 不使用魔法棒: