1 条题解
-
0
题解
问题分析
题目要求将数组划分为 个连续非空子段,使得最大子段和与最小子段和的差值最大。
关键观察
- 最大化不平衡度 = 最大化最大子段和 - 最小子段和
- 由于所有元素非负,最大子段和可以通过合并多个元素获得
- 最小子段和可以通过单个小元素获得
算法思路
分类讨论法:
情况1:
- 只有一种划分方式:在某个位置 切一刀
- 不平衡度 =
- 遍历所有分割点取最大值
情况2:
策略:让一个子段尽可能大,另一个子段尽可能小
三种可能的最优方案:
-
最小子段在中间:
- 选择一个元素 作为单独子段(最小值)
- 左边取尽可能长的连续段(但不能太长以免影响段数)
- 右边取尽可能长的连续段
- 不平衡度 =
-
最小子段在两端:
- 使用滑动窗口找长度为 的最大子段和
- 最小子段是剩余部分中的最小值
- 不平衡度 = 最大窗口和 - 剩余部分的最小值
核心代码逻辑
的情况
for (int i = 1; i < n; i++) { ans = std::max(ans, std::abs(s[i] * 2 - s[n])); }的情况
-
中间最小段:
// 左边连续段 + 右边连续段 - 中间单独段 ans = std::max(ans, s[i] - s[l] + s[r] - s[i+1] - a[i]); -
两端最小段:
// 长度为(n-k+1)的最大窗口和 - 剩余部分的最小值 ans = std::max(ans, s[r] - s[l] - std::min(pre[l], suf[r]));
复杂度分析
- 预处理: 计算前缀和、前缀最小值、后缀最小值
- : 遍历分割点
- : 遍历所有可能的最小子段位置
- 总复杂度:
算法步骤
- 读入 和数组
- 计算前缀和数组
- 根据 值选择不同策略:
- :遍历分割点计算差值
- :
- 考虑中间最小段的情况
- 考虑两端最小段的情况
- 输出最大不平衡度
算法标签
- 贪心算法
- 前缀和
- 滑动窗口
- 分类讨论
- 最优化问题
- 1
信息
- ID
- 3935
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者