合并石子获得最大得分问题(带权值版本)
字数 3920 2025-12-05 14:37:31

合并石子获得最大得分问题(带权值版本)

题目描述
假设有 n 堆石子排成一行,每堆石子有一个重量值 w[i](正整数),以及一个附加权值 v[i](可正可负)。你可以进行 n-1 次合并操作,每次合并选择相邻的两堆石子 i 和 i+1,将它们合并为一堆新的石子,新石子的重量为两堆石子重量之和,而本次合并的得分为:

(w[i] + w[i+1]) * (v[i] + v[i+1])

合并后,新石子的重量为 w[i] + w[i+1],附加权值为 v[i] + v[i+1]。合并后原两堆石子消失,新石子占据原两堆的位置(即序列长度减 1)。目标是选择合并的顺序,使得总得分最大

示例
n = 3
重量 w = [2, 3, 4]
权值 v = [1, -1, 2]
一种合并顺序:

  1. 先合并前两堆:得分 = (2+3)(1+(-1)) = 50 = 0,新石子重量=5,权值=0,序列变为 [5,4] 和 [0,2]。
  2. 合并剩下两堆:得分 = (5+4)(0+2) = 92 = 18,总得分 = 0+18 = 18。
    另一种合并顺序可能得到不同总分,需要找出最大值。

解题过程

步骤 1:理解问题结构

这是一个区间动态规划问题,因为:

  • 每次合并相邻两堆,类似石子合并经典问题。
  • 合并后的新石子有新的重量和权值,会影响后续合并的得分。
  • 需要按不同顺序尝试,找到最大总分。

设:

  • w[i] 为第 i 堆初始重量。
  • v[i] 为第 i 堆初始权值。

合并区间 [i, j] 时,最终合并成一堆,其总重量是固定的,为 sum(w[i..j]),与合并顺序无关。
总权值也是固定的,为 sum(v[i..j]),也与合并顺序无关。
为什么?因为每次合并只是把两堆的重量和权值分别相加,加法满足结合律,所以最终的总重量和总权值不变。

得分与合并顺序有关,因为得分计算式为 (w_left + w_right) * (v_left + v_right),其中 w_left 和 v_left 是左区间合并后的总重量和总权值,w_right 和 v_right 是右区间合并后的总重量和总权值。
不同的合并顺序会导致不同的中间合并时的左右重量和权值组合,从而影响得分。


步骤 2:定义状态

设:

  • dp[i][j] 表示将区间 [i, j] 的石子合并成一堆时,能获得的最大总得分(i ≤ j)。
  • sumW[i][j] 表示区间 [i, j] 的石子总重量,可前缀和快速计算。
  • sumV[i][j] 表示区间 [i, j] 的石子总权值,同样可前缀和计算。

注意:区间 [i, j] 合并成一堆后,它的总重量 = sumW[i][j],总权值 = sumV[i][j],这是确定的,与怎么合并无关。


步骤 3:状态转移

考虑最后一次合并区间 [i, j] 时,一定是将 [i, k] 合并成的一堆与 [k+1, j] 合并成的一堆进行合并(i ≤ k < j)。

合并的得分是:
(sumW[i][k] + sumW[k+1][j]) * (sumV[i][k] + sumV[k+1][j]) 吗?
不对!因为合并时刻,左右两堆各自已经是合并后的一堆,它们的重量就是 sumW[i][k] 和 sumW[k+1][j],权值就是 sumV[i][k] 和 sumV[k+1][j],所以得分就是:
sumW[i][k] * sumV[k+1][j] + sumW[k+1][j] * sumV[i][k]?让我们展开:

得分 = (sumW[i][k] + sumW[k+1][j]) * (sumV[i][k] + sumV[k+1][j])
= sumW[i][k]sumV[i][k] + sumW[i][k]sumV[k+1][j] + sumW[k+1][j]sumV[i][k] + sumW[k+1][j]sumV[k+1][j]

但 sumW[i][k]sumV[i][k] 并不是 dp[i][k] 的得分总和,dp[i][k] 是区间 [i,k] 内部合并得到的总得分,最后合并成的一堆重量为 sumW[i][k],权值为 sumV[i][k],但没有一项得分是 sumW[i][k]sumV[i][k]。
所以不能直接这样拆。

实际上,最后一步合并的得分是:
(sumW[i][k] + sumW[k+1][j]) * (sumV[i][k] + sumV[k+1][j])
= (sumW[i][k] + sumW[k+1][j])*(sumV[i][k] + sumV[k+1][j])
这是没有问题的,这就是最后一步的得分。

那么 dp[i][j] = max over k of { dp[i][k] + dp[k+1][j] + 最后一步得分 }。

注意:dp[i][k] 是 [i,k] 内部合并的最大得分,它不影响总重量和总权值,只影响内部得分累加。
同理 dp[k+1][j] 是 [k+1,j] 内部的最大得分。

所以状态转移方程为:
dp[i][j] = max{ dp[i][k] + dp[k+1][j] + (sumW[i][k] + sumW[k+1][j]) * (sumV[i][k] + sumV[k+1][j]) }
其中 i ≤ k < j。


步骤 4:初始化

当区间长度 len = 1 时,只有一堆石子,不需要合并,得分 = 0。
所以 dp[i][i] = 0。

当区间长度 len = 2 时,只有一种合并方式,k 只能等于 i,
dp[i][i+1] = 0 + 0 + (w[i] + w[i+1]) * (v[i] + v[i+1])。

为了快速求 sumW 和 sumV,我们可以用前缀和数组:
prefixW[t] = sum(w[0..t-1]),则 sumW[i][j] = prefixW[j+1] - prefixW[i]。
同理 prefixV[t] = sum(v[0..t-1])。


步骤 5:计算顺序

按照区间长度 len 从小到大计算,len 从 2 到 n。
对于每个 len,枚举起点 i,则 j = i + len - 1。
枚举分割点 k 从 i 到 j-1。


步骤 6:最终答案

dp[0][n-1] 就是将整个区间合并成一堆的最大总得分。


步骤 7:示例推演

用示例 n=3, w=[2,3,4], v=[1,-1,2] 来验证。

前缀和 weight:
pw[0]=0, pw[1]=2, pw[2]=5, pw[3]=9。
sumW[0][0]=2, sumW[0][1]=5, sumW[0][2]=9, sumW[1][1]=3, sumW[1][2]=7, sumW[2][2]=4。

前缀和 value:
pv[0]=0, pv[1]=1, pv[2]=0, pv[3]=2。
sumV[0][0]=1, sumV[0][1]=0, sumV[0][2]=2, sumV[1][1]=-1, sumV[1][2]=1, sumV[2][2]=2。

初始化 dp[i][i]=0。

len=2:
dp[0][1] = dp[0][0]+dp[1][1]+(sumW[0][0]+sumW[1][1])(sumV[0][0]+sumV[1][1])
= 0+0+(2+3)
(1+(-1)) = 50=0。
dp[1][2] = 0+0+(3+4)
((-1)+2) = 7*1=7。

len=3:
i=0,j=2
k=0: dp[0][0]+dp[1][2]+(sumW[0][0]+sumW[1][2])(sumV[0][0]+sumV[1][2])
= 0+7+(2+7)
(1+1) = 7+92=25。
k=1: dp[0][1]+dp[2][2]+(sumW[0][1]+sumW[2][2])
(sumV[0][1]+sumV[2][2])
= 0+0+(5+4)(0+2)=92=18。
max(25,18) = 25。

所以最大得分是 25。
之前示例的第二种顺序(先合并后两堆再合并前一堆)能得到 25 吗?
先合并后两堆:
合并 (3,4): 得分=(3+4)(-1+2)=71=7,新堆重量=7,权值=1,序列变为 [2,7] 和 [1,1]。
合并 (2,7): 得分=(2+7)(1+1)=92=18,总得分=7+18=25。
是的,符合 DP 结果。


总结

这个题目的区间 DP 状态定义清晰,关键是理解合并的得分公式和区间合并时的可加性。
转移方程利用了最后一步合并的得分计算,并分解为左右子区间的 dp 值加上最后一步得分。
计算时注意前缀和预处理以便 O(1) 得到区间重量和与权值和。
时间复杂度 O(n³),空间复杂度 O(n²)。

合并石子获得最大得分问题(带权值版本) 题目描述 假设有 n 堆石子排成一行,每堆石子有一个重量值 w[ i](正整数),以及一个附加权值 v[ i](可正可负)。你可以进行 n-1 次合并操作,每次合并选择相邻的两堆石子 i 和 i+1,将它们合并为一堆新的石子,新石子的重量为两堆石子重量之和,而本次合并的 得分 为: (w[i] + w[i+1]) * (v[i] + v[i+1]) 合并后,新石子的重量为 w[i] + w[i+1] ,附加权值为 v[i] + v[i+1] 。合并后原两堆石子消失,新石子占据原两堆的位置(即序列长度减 1)。目标是选择合并的顺序,使得 总得分最大 。 示例 n = 3 重量 w = [ 2, 3, 4 ] 权值 v = [ 1, -1, 2 ] 一种合并顺序: 先合并前两堆:得分 = (2+3) (1+(-1)) = 5 0 = 0,新石子重量=5,权值=0,序列变为 [ 5,4] 和 [ 0,2 ]。 合并剩下两堆:得分 = (5+4) (0+2) = 9 2 = 18,总得分 = 0+18 = 18。 另一种合并顺序可能得到不同总分,需要找出最大值。 解题过程 步骤 1:理解问题结构 这是一个 区间动态规划 问题,因为: 每次合并相邻两堆,类似石子合并经典问题。 合并后的新石子有新的重量和权值,会影响后续合并的得分。 需要按不同顺序尝试,找到最大总分。 设: w[i] 为第 i 堆初始重量。 v[i] 为第 i 堆初始权值。 合并区间 [ i, j] 时,最终合并成一堆,其 总重量 是固定的,为 sum(w[ i..j ]),与合并顺序无关。 但 总权值 也是固定的,为 sum(v[ i..j ]),也与合并顺序无关。 为什么?因为每次合并只是把两堆的重量和权值分别相加,加法满足结合律,所以最终的总重量和总权值不变。 但 得分 与合并顺序有关,因为得分计算式为 (w_left + w_right) * (v_left + v_right) ,其中 w_ left 和 v_ left 是左区间合并后的总重量和总权值,w_ right 和 v_ right 是右区间合并后的总重量和总权值。 不同的合并顺序会导致不同的中间合并时的左右重量和权值组合,从而影响得分。 步骤 2:定义状态 设: dp[i][j] 表示将区间 [ i, j] 的石子合并成一堆时,能获得的 最大总得分 (i ≤ j)。 sumW[i][j] 表示区间 [ i, j ] 的石子总重量,可前缀和快速计算。 sumV[i][j] 表示区间 [ i, j ] 的石子总权值,同样可前缀和计算。 注意:区间 [ i, j] 合并成一堆后,它的总重量 = sumW[ i][ j],总权值 = sumV[ i][ j ],这是确定的,与怎么合并无关。 步骤 3:状态转移 考虑最后一次合并区间 [ i, j] 时,一定是将 [ i, k] 合并成的一堆与 [ k+1, j] 合并成的一堆进行合并(i ≤ k < j)。 合并的得分是: (sumW[i][k] + sumW[k+1][j]) * (sumV[i][k] + sumV[k+1][j]) 吗? 不对!因为合并时刻,左右两堆各自已经是合并后的一堆,它们的重量就是 sumW[ i][ k] 和 sumW[ k+1][ j],权值就是 sumV[ i][ k] 和 sumV[ k+1][ j ],所以得分就是: sumW[i][k] * sumV[k+1][j] + sumW[k+1][j] * sumV[i][k] ?让我们展开: 得分 = (sumW[ i][ k] + sumW[ k+1][ j]) * (sumV[ i][ k] + sumV[ k+1][ j ]) = sumW[ i][ k] sumV[ i][ k] + sumW[ i][ k] sumV[ k+1][ j] + sumW[ k+1][ j] sumV[ i][ k] + sumW[ k+1][ j] sumV[ k+1][ j ] 但 sumW[ i][ k] sumV[ i][ k] 并不是 dp[ i][ k] 的得分总和,dp[ i][ k] 是区间 [ i,k] 内部合并得到的总得分,最后合并成的一堆重量为 sumW[ i][ k],权值为 sumV[ i][ k],但 没有 一项得分是 sumW[ i][ k] sumV[ i][ k ]。 所以不能直接这样拆。 实际上,最后一步合并的得分是: (sumW[i][k] + sumW[k+1][j]) * (sumV[i][k] + sumV[k+1][j]) = (sumW[ i][ k] + sumW[ k+1][ j])* (sumV[ i][ k] + sumV[ k+1][ j ]) 这是没有问题的,这就是最后一步的得分。 那么 dp[ i][ j] = max over k of { dp[ i][ k] + dp[ k+1][ j ] + 最后一步得分 }。 注意:dp[ i][ k] 是 [ i,k ] 内部合并的最大得分,它不影响总重量和总权值,只影响内部得分累加。 同理 dp[ k+1][ j] 是 [ k+1,j ] 内部的最大得分。 所以状态转移方程为: dp[i][j] = max{ dp[i][k] + dp[k+1][j] + (sumW[i][k] + sumW[k+1][j]) * (sumV[i][k] + sumV[k+1][j]) } 其中 i ≤ k < j。 步骤 4:初始化 当区间长度 len = 1 时,只有一堆石子,不需要合并,得分 = 0。 所以 dp[ i][ i ] = 0。 当区间长度 len = 2 时,只有一种合并方式,k 只能等于 i, dp[ i][ i+1] = 0 + 0 + (w[ i] + w[ i+1]) * (v[ i] + v[ i+1 ])。 为了快速求 sumW 和 sumV,我们可以用前缀和数组: prefixW[ t] = sum(w[ 0..t-1]),则 sumW[ i][ j] = prefixW[ j+1] - prefixW[ i ]。 同理 prefixV[ t] = sum(v[ 0..t-1 ])。 步骤 5:计算顺序 按照区间长度 len 从小到大计算,len 从 2 到 n。 对于每个 len,枚举起点 i,则 j = i + len - 1。 枚举分割点 k 从 i 到 j-1。 步骤 6:最终答案 dp[ 0][ n-1 ] 就是将整个区间合并成一堆的最大总得分。 步骤 7:示例推演 用示例 n=3, w=[ 2,3,4], v=[ 1,-1,2 ] 来验证。 前缀和 weight: pw[ 0]=0, pw[ 1]=2, pw[ 2]=5, pw[ 3 ]=9。 sumW[ 0][ 0]=2, sumW[ 0][ 1]=5, sumW[ 0][ 2]=9, sumW[ 1][ 1]=3, sumW[ 1][ 2]=7, sumW[ 2][ 2 ]=4。 前缀和 value: pv[ 0]=0, pv[ 1]=1, pv[ 2]=0, pv[ 3 ]=2。 sumV[ 0][ 0]=1, sumV[ 0][ 1]=0, sumV[ 0][ 2]=2, sumV[ 1][ 1]=-1, sumV[ 1][ 2]=1, sumV[ 2][ 2 ]=2。 初始化 dp[ i][ i ]=0。 len=2: dp[ 0][ 1] = dp[ 0][ 0]+dp[ 1][ 1]+(sumW[ 0][ 0]+sumW[ 1][ 1]) (sumV[ 0][ 0]+sumV[ 1][ 1 ]) = 0+0+(2+3) (1+(-1)) = 5 0=0。 dp[ 1][ 2] = 0+0+(3+4) ((-1)+2) = 7* 1=7。 len=3: i=0,j=2 k=0: dp[ 0][ 0]+dp[ 1][ 2]+(sumW[ 0][ 0]+sumW[ 1][ 2]) (sumV[ 0][ 0]+sumV[ 1][ 2 ]) = 0+7+(2+7) (1+1) = 7+9 2=25。 k=1: dp[ 0][ 1]+dp[ 2][ 2]+(sumW[ 0][ 1]+sumW[ 2][ 2]) (sumV[ 0][ 1]+sumV[ 2][ 2 ]) = 0+0+(5+4) (0+2)=9 2=18。 max(25,18) = 25。 所以最大得分是 25。 之前示例的第二种顺序(先合并后两堆再合并前一堆)能得到 25 吗? 先合并后两堆: 合并 (3,4): 得分=(3+4) (-1+2)=7 1=7,新堆重量=7,权值=1,序列变为 [ 2,7] 和 [ 1,1 ]。 合并 (2,7): 得分=(2+7) (1+1)=9 2=18,总得分=7+18=25。 是的,符合 DP 结果。 总结 这个题目的区间 DP 状态定义清晰,关键是理解合并的得分公式和区间合并时的可加性。 转移方程利用了最后一步合并的得分计算,并分解为左右子区间的 dp 值加上最后一步得分。 计算时注意前缀和预处理以便 O(1) 得到区间重量和与权值和。 时间复杂度 O(n³),空间复杂度 O(n²)。