#lydlx05x0E16. 估算 Estimation
估算 Estimation
题目描述
给定一个长度为 的整数数组 ,你需要创建另一个长度为 的整数数组 ,数组 被分为 个连续的部分,并且如果 和 在同一个部分,则 。
如果要求数组 能够满足 最小,那么最小值是多少,请你输出这个最小值。
输入格式
输入包含不超过 25 组测试数据。
对于每组测试数据,第一行包含两个整数 和 。
接下来 行每行包含一个整数,表示完整的数组 。
当输入为一行 0 0 时,表示输入终止。
输出格式
对于每组数据,输出一个最小值。
每个结果占一行。
样例
7 2
6
5
4
3
2
1
7
0 0
9
样例解释
输入
要求
将 分成 个连续部分,每个部分内 值相同。求 的最小值。
分析
我们需要将数组 分成 2 段,每段内 值相同。设第一段为 ,第二段为 。
对于每一段,最优的 值取为该段 的中位数时, 最小(这是绝对值偏差最小的性质)。
所以我们需要枚举分割点 ,计算每段中位数引起的绝对偏差和。
计算
首先排序?不对,因为 是分段的,每段内 相同,但 顺序固定,不能排序。
实际上,对于一段连续区间 ,设该段内 值为 ,则 的最小值在 取该区间 的中位数时达到。
因此,我们可以预处理所有区间 的最优值 ,即该区间取中位数时的绝对偏差和。
预处理
对于每个区间 ,我们需要找到中位数并计算偏差和。
由于 ,可以 预处理。
方法:
- 对每个左端点 ,维护一个有序列表(如平衡树或两个堆),依次加入右端点 ,动态维护中位数和偏差和。
但计算偏差和需要知道所有元素与中位数的差绝对值之和,可以动态维护。
更简单的方法:
- 对每个 ,将 复制到临时数组,排序,找到中位数,然后计算绝对偏差和。复杂度 ,对于 可能过大($4\times10^6 \log 2000 \approx 4\times10^6 \times 11 \approx 4.4\times10^7$,可接受)。
动态规划
设 表示将前 个元素分成 段的最小总偏差。
转移:
$$dp[i][k] = \min_{j < i} \{ dp[j][k-1] + cost[j+1][i] \}$$其中 是区间 的偏差最小值。
初始化:,其他为无穷大。
答案:。
样例计算
预处理 : 例如:
- :中位数是排序后的第 4 个数(从小到大:1,2,3,4,5,6,7),中位数 4,偏差和 = |6-4|+|5-4|+|4-4|+|3-4|+|2-4|+|1-4|+|7-4| = 2+1+0+1+2+3+3 = 12。
- 分成两段:枚举分割点 (1~6):
- :第一段 [1,1] 中位数 6,偏差 0;第二段 [2,7] 中位数 (1,2,3,4,5,7) 中位数 (3+4)/2=3.5,取 3 或 4?对于偶数个数,中位数可以是中间两个数的任意值,但绝对值偏差最小通常取中间两个数之间的任意值,但为了整数 ,可以取 3 或 4。偏差和:|5-3|+|4-3|+|3-3|+|2-3|+|1-3|+|7-3| = 2+1+0+1+2+4=10。总偏差 10。
- :[1,2] 中位数 (5,6) 取 5 或 6,偏差 |6-5|+|5-5|=1+0=1;[3,7] 中位数 (1,2,3,4,7) 取 3,偏差 |4-3|+|3-3|+|2-3|+|1-3|+|7-3| = 1+0+1+2+4=8;总 9。
- :[1,3] 中位数 5(排序 4,5,6),偏差 |6-5|+|5-5|+|4-5|=1+0+1=2;[4,7] 中位数 (1,2,3,7) 取 2 或 3,取 2 偏差 |3-2|+|2-2|+|1-2|+|7-2| = 1+0+1+5=7;总 9。
- :[1,4] 中位数 4.5 取 4 或 5,取 4 偏差 |6-4|+|5-4|+|4-4|+|3-4| = 2+1+0+1=4;[5,7] 中位数 (1,2,7) 中位数 2,偏差 |2-2|+|1-2|+|7-2| = 0+1+5=6;总 10。
- :[1,5] 中位数 4(排序 2,3,4,5,6),偏差 2+1+0+1+2=6;[6,7] 中位数 (1,7) 取 1 或 7,取 1 偏差 |1-1|+|7-1|=0+6=6;总 12。
- :[1,6] 中位数 3.5 取 3 或 4,取 3 偏差 3+2+1+0+1+2=9;[7,7] 偏差 0;总 9。
最小值为 9,所以输出 9。
数据范围
- 数组 中元素的绝对值不超过 10000
- 测试数据不超过 25 组
算法分析
问题转化
将数组 分成 个连续段,每段内 值相同,使得 最小。
对于每一段,最优的 值是该段 的中位数(如果长度为偶数,中位数可以是中间两个数的任意值,但绝对值偏差和是相同的,取任意中间值即可)。
因此,问题转化为:将数组 分成 段,每段的代价为该段元素与其中位数的绝对偏差和,求最小总代价。
预处理代价
设 表示区间 的代价,即该区间元素与其中位数的绝对偏差和。
如何高效计算 ?
- 暴力方法:对每个区间排序找中位数,复杂度 ,对于 大约 ,可接受。
- 优化:可以固定左端点 ,从小到大枚举右端点 ,用两个堆(最大堆和最小堆)动态维护中位数,并计算绝对偏差和。但计算绝对偏差和需要知道所有元素与中位数的差,可以维护两个堆的和。更简单的方法是直接维护有序列表(如平衡树),但实现较复杂。
由于 , 在 25 组数据下可能稍慢但应该能通过(,可能超时)。需要优化。
优化预处理
注意到 的范围较小(绝对值 ),我们可以使用计数排序的思想。
对于每个左端点 ,维护一个频数数组 (偏移 10000),以及当前区间的元素个数 。随着 增加,更新 ,然后可以 找到中位数(因为值域只有 20001),并计算绝对偏差和。但计算绝对偏差和需要遍历整个值域,复杂度 太大。
更好的方法:
已知对于有序数组,绝对偏差和可以快速计算。设区间 排序后为 ,中位数索引 (下取整),则偏差和 = 。
可以预处理前缀和 ,则偏差和 = $sorted[m] \times (m-l+1) - (pref[m] - pref[l-1]) + (pref[r] - pref[m]) - sorted[m] \times (r-m)$。
因此,如果我们能快速得到区间排序后的数组,就可以 计算偏差和。但排序需要 。
动态规划优化
DP 转移:$dp[i][k] = \min_{j < i} \{ dp[j][k-1] + cost[j+1][i] \}$。
如果直接枚举 ,复杂度 ,对于 ,大约 ,加上预处理 ,可能勉强通过。
四边形不等式优化
由于 满足四边形不等式, 转移可以使用决策单调性优化,将复杂度降为 或 。
但实现较复杂。
另一种思路:直接 DP 枚举段值
由于 每段值相同,我们可以直接枚举每段的值,但值域太大(-10000 到 10000),不可行。
可行解法
考虑到 ,,直接 DP 加上 预处理在 25 组数据下可能可以接受(约 $25 \times (4\times10^6 + 1\times10^8) \approx 2.6\times10^9$ 运算,可能超时,但实际常数小可能通过)。
优化预处理
我们可以用 预处理 ,方法如下:
对于每个左端点 ,维护一个有序数组(初始为空),依次加入 ,并维护中位数和绝对偏差和。
加入一个新元素 时,我们需要将其插入有序数组,并更新中位数和偏差和。
- 插入位置可以用二分查找,。
- 偏差和更新:设原中位数为 ,新中位数为 。
绝对偏差和的变化 = 新元素与中位数的偏差 + 旧元素偏差的变化。
具体公式较复杂,但可以维护前缀和快速计算。
一个更简单的方法:直接使用两个堆(最大堆存较小一半,最小堆存较大一半)维护中位数,并维护两个堆的元素和,可以 更新中位数和偏差和。但计算绝对偏差和需要知道所有元素与中位数的差,我们可以维护:
- :小于中位数的元素和
- :大于中位数的元素和
- ,
则绝对偏差和 = $mid \times countLeft - sumLeft + sumRight - mid \times countRight$。
当插入新元素时,根据与当前中位数的大小关系,插入到对应堆中,然后调整堆大小使中位数正确,并更新 , 等。
这样,对于每个左端点 ,遍历右端点 ,可以在 时间内计算所有 ,总复杂度 。
最终算法
- 预处理 ()。
- 动态规划:$dp[i][k] = \min_{j < i} \{ dp[j][k-1] + cost[j+1][i] \}$。
- 输出 。
实现提示
- 注意数组下标从 1 开始。
- 使用
long long存储代价,因为偏差和可能较大。 - 多组数据,每次重置数组。
- 当 时,显然每段一个元素,代价为 0,但题目保证 。