—题意
题意:定义一个数字 $num$ 在一个数组中的贡献为 最后一次出现的下标 减去 第一次出现的下标;
定义一个数组的价值 $cost$ 为该数组中出现过的数字 $num$ 的价值总和;
如数组 $[2,2,3,2,3]$,**$cost$** $= (4-1)+(5-3) = 5$;
给定 $n$ ,$mv,以及长度为 $n$ 的数组 **$a[]$**;
求将 $a[]$ 分成 $m$ 段数组产生的最小 $cost$ 总和;
—瞎想
$dp[i][j]$ 表示将前 $j$ 个数字分为 $i$ 段产生的最小 $cost$;
$c[i][j]$ 表示数组下标 $[i,j]$ 划分为一段的贡献;
那么 $dp[i][j] = min( dp[i-1][k] + c[k+1][j] )$ 其中 $k$ 小于 $j$,按照这样暴力来一遍,哦吼~,T飞!;
既然 $dp$ 方程写出来了,考虑如何优化;
—优化
对于上面所举的例子 $[2,2,3,2,3]$,也可以等于 $cost = (2-1)+(4-2)+(5-3)$;
也就是将某个数字的 $num$ 细分,数字 $2$ 就是 ( 这次出现位置 $-$ 上次出现位置 ) 的总和;
$dp[i]$ 都是由 $dp[i-1]$ 而来的,也就是外层 $for$ 层数 $i$ ;
内层 $for$ 新加入的数字 $a[j]$,也就是移动 $j$ 指针,考虑 $dp$ 式子右侧中 $dp[i-1][k] + c[k+1][j],(k < j)$;
每移动一次 $j$ 指针,记 $a[j]$ 上一次出现的位置为 $pos$,如果将 $[pos,j]$ 作为新的一段,那么 $dp[i-1][ 0 ~ pos-1 ]$ 的值都需要加上 $j-pos$;
此时的 $k$ 在 $[0,j-1]$ 范围内,需要查找 $[0,j-1]$ 范围内的最小值;
所以用线段树维护区间最小值来优化$dp$,每次移动 $j$ 指针复杂度为$logn$,全局 $O(nmlogn)$;
—代码
1 |
|