题解 Ina of the Mountain
CF1852C Ina of the Mountain 题解
首先将题目进行一定的转化,注意到对于一个章鱼(数字)
假设确定了每个章鱼需要被执行的操作次数为
不妨将每个章鱼的取值看作高度,将一个章鱼需要被操作的次数加上
假设已经确定了
- 若
h_{i+1} \le h_i ,那么可以直接不做任何提升操作。 -
若
h_{i + 1} \gt h_i ,有以下两种选择:- 不做任何抬升操作,将答案增加
h_{i + 1} - h_{i} ; - 选择一个
j \le i ,使得h_j + k - h_{j- 1} - \max(0, h_j - h_{j - 1}) 最小(这个最小值后文记作\Delta_i ),并提升[j, i] 范围中的每个章鱼,将答案增加\Delta_i 。
- 不做任何抬升操作,将答案增加
第一种操作很好理解,第二种操作的思想是将新增的章鱼前的章鱼提升,使得新增的章鱼不对答案产生贡献。同时,容易得知,如果选定一个章鱼,并将其及其后所有章鱼提升,其后章鱼产生的贡献不变,只有被选定的章鱼贡献产生变化。可参考下图。
在两种操作中选择一个贡献较小的,就完成了第
这里按照这个思路直接模拟两种操作即可,不提供参考代码。
然而,每新增一个章鱼,这种方法就要向前遍历每一个章鱼,时间复杂度为
优先队列优化
注意到,在上面的方法中,每个
引入优先队列进行优化后,每个章鱼需要花费
参考代码
void work()
{
int n, k;
cin >> n >> k;
vector<int> arr(n + 2);
for (int i = 1; i <= n; i++)
{
cin >> arr[i];
arr[i] %= k;
}
priority_queue<long long, vector<long long>, greater<long long>> q;
long long ans = 0;
for (int i = 1; i <= n + 1; i++)
{
if (arr[i - 1] == arr[i]) continue;
if (arr[i - 1] > arr[i])
{
q.push(arr[i] + k - arr[i - 1]);
}
else // arr[i - 1] < arr[i]
{
q.push(arr[i] - arr[i - 1]);
ans += q.top();
q.pop();
}
}
cout << ans << endl;
}