问题分析
该问题的核心在于通过最小化插入操作次数,使得数组的平滑值(相邻元素最大差绝对值)恰好等于 。
这包含两个核心约束:
- 上限约束 (Upper Bound):修改后的数组中,任意相邻两数的差的绝对值不能超过
。
- 存在性约束 (Existence):修改后的数组中,必须至少存在一对相邻数值,其差的绝对值恰好等于
。
由于题目要求“最小操作次数”,且对每一对相邻元素的处理是相互独立的(在两数之间插入数字不会影响这对数之外的其他差值),这显然是一个基于贪心算法 的问题。
核心算法
我们将问题分解为针对每一个相邻数对 的处理。设当前相邻差值为
。
-
处理“上限约束” (消除大于
的差值): 如果
,则当前的差值破坏了平滑值不超过
的条件。我们需要在
和
之间插入若干个整数,将这段距离“切分”成若干个长度不大于
的段。
- 最优切分逻辑:为了使操作次数最少,我们应当让每一段的长度尽可能接近
。
- 数学推导:将长度
切分为每段最大长度为
,所需的最少段数为
。由于每增加一个插入点,段数增加 1,因此需要的插入操作次数为:
或者在编程中更常用的整数运算公式:
(其中
//表示整数除法)。
- 最优切分逻辑:为了使操作次数最少,我们应当让每一段的长度尽可能接近
-
处理“存在性约束” (确保最大值为
):
-
情况 A:原始数组的最大差值
根据贪心逻辑,我们为了满足上限约束,必须对大于
的区间进行切分。只要
,我们总能构造出一种切分方案,使得切分后的某一段长度恰好为
,其余段长度
。 例如:
。需插入1个数。我们可以插入一个数使得两段分为
和
。满足最大值为 3。 因此,如果进行了切分操作,我们可以默认最终的平滑值一定可以取到
。
-
情况 B:原始数组的最大差值
不需要任何操作,上限和存在性均已满足。操作数为 0。
-
情况 C:原始数组的最大差值
此时数组中所有相邻差值都小于
。如果不进行操作,最大平滑值小于
,不满足目标。 我们需要人为地制造一个差值为
的相邻对。
- 我们可以在任意两个数之间插入一个数,使得新构成的两个差值中,最大的那个恰好为
。
- 例如:在
之间插入
。令
。由于原差值
,根据三角不等式,另一段差值
。只要我们选择的
合理,只需1次操作即可将平滑值提升到
(且不破坏上限约束,因为另一段虽然可能变大,但可以通过调整使其
。实际上更简单的构造是直接插入一个数造成局部“尖峰”)。
- 结论:如果所有
,我们需要额外增加 1 次操作(除非题目隐含数值必须在
区间内,但题目描述为“插入一个整数”,通常不限制数值范围,且为了满足题目必定有解,允许制造尖峰)。
- 我们可以在任意两个数之间插入一个数,使得新构成的两个差值中,最大的那个恰好为
-
代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
ll k;
cin >> n >> k;
vector<ll> diff(n - 1);
ll maxD = 0LL;
ll last = 0LL;
ll res = 0LL;
for (int i = 0; i < n; i++) {
ll a;
cin >> a;
ll curD = 0LL;
if (last > 0) {
curD = abs(a - last);
if (curD > k)
res += (curD - 1) / k;
maxD = max(maxD, curD);
}
last = a;
}
if (maxD < k) {
cout << "1\n";
} else {
cout << res << "\n";
}
}

京公网安备 11010502036488号