1 条题解
-
0
题意回顾
有 瓶橙汁排成一排,第 瓶的品牌为 。
可以花费 的代价交换相邻两瓶橙汁。
求最小代价,使得最左边 瓶橙汁品牌两两不同。如果无法实现,输出 。
数据范围:,。
初步分析
1. 可行性判断
如果整个序列中不同品牌的数量少于 ,那么肯定无法使前 个品牌两两不同,输出 。
2. 问题转化
交换相邻元素的最小代价实际上就是逆序对相关的概念。
更准确地说,把一个元素从位置 移动到位置 ()的最小代价是 (因为只能相邻交换)。我们的目标:选择 个不同的品牌,让它们占据前 个位置,且移动总代价最小。
关键观察
1. 问题重述
我们需要从序列中选出 个不同品牌的瓶子,让它们占据位置 到 ,并且移动总距离最小。
每个瓶子 (品牌为 )如果被选入前 个位置,设它最终在位置 (),那么移动代价为:
- 如果 ,代价 = (向左移动)
- 如果 ,这种情况不会发生,因为我们总是用右边的瓶子填补左边空缺
实际上,由于我们只能交换相邻瓶子,把位置 的瓶子移动到位置 的代价就是 (当 )。
2. 最优策略
对于前 个位置中的每个位置 ,我们应该选择尽可能靠左的瓶子来占据它,但要满足品牌不同的约束。
更形式化地说:
- 我们要为位置 分配 个不同品牌的瓶子
- 每个品牌只能出现一次
- 最小化 ,其中 是分配给位置 的瓶子的原始位置
即最小化 。
因此,问题转化为:选择 个不同品牌的瓶子,它们的原始位置之和最小。
贪心算法
算法步骤
- 检查可行性:统计所有不同品牌数,如果小于 则输出
- 记录每个品牌的所有出现位置
- 贪心选择:对于每个品牌,我们只关心它最左边的出现位置,因为这样能使位置和最小
- 选择最小的 k 个位置:从所有品牌的最左位置中,选择最小的 个
- 计算答案:
- 每个品牌只需要出现一次在前 个位置中
- 为了最小化总移动代价,我们应选择每个品牌出现位置最靠前的那个
- 然后从这些最前位置中挑选最小的 个(因为位置编号越小,移动代价越小)
算法实现细节
数据结构
- 用数组
first_occurrence[b]记录品牌 第一次出现的位置 - 如果某个品牌没有出现,设为无穷大
- 收集所有品牌的第一次出现位置,排序,取前 小的
复杂度
- 统计第一次出现位置:
- 排序:(最多 个不同品牌)
- 总复杂度:,可过
样例验证
样例 1
各品牌第一次出现位置:
- 品牌3:位置1
- 品牌1:位置4
- 品牌2:位置5
最小的3个位置:
总代价 = ✓
样例 2
不同品牌数 = 1 < 2,输出 ✓
边界情况
- :代价总是 (第一个瓶子已经在位置1)
- :需要所有品牌都不同,否则输出
- 有品牌在位置 :不会发生
总结
本题的关键转化:
- 将相邻交换代价转化为位置差
- 发现问题等价于选择 个不同品牌瓶子的最小位置和
- 每个品牌只需考虑最左出现位置
- 贪心选择最小的 个位置
通过这种转化,将看似复杂的交换问题转化为简单的贪心选择问题,时间复杂度 ,可处理 的数据规模。
- 1
信息
- ID
- 4418
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者