1 条题解
-
0
根据标程,对题目 1931C - Make Equal Again 的详细题解如下:
题意简述
给定一个长度为 的整数数组 ,你可以最多一次操作:选择一段连续区间 和一个值 ,将该区间内所有元素赋值为 ,花费为区间长度 。
问:最少花费多少 burles,能使数组中所有元素相等?
思路分析
1. 特殊情况
如果数组中所有元素已经相等,则不需要任何操作,答案为 。
2. 一般情况
因为只能进行一次区间赋值,并且希望花费最小(即区间长度最小),
我们应当尽可能保留数组两端已经相等的部分,只修改中间一段。
3. 核心观察
设:
- = 数组最长的相等前缀的长度(所有元素都等于 )
- = 数组最长的相等后缀的长度(所有元素都等于 )
情况 1:
此时,前缀和后缀的值相同。
我们可以同时保留前缀和后缀,只修改中间的部分。
那么:- 保留的元素数量 =
- 需要修改的元素数量 =
- 答案 =
情况 2:
此时,前缀和后缀的值不同。
我们只能选择保留较长的那一段(因为一次操作只能赋一个值,不能同时保留两端不同的值)。
那么:- 保留的元素数量 =
- 需要修改的元素数量 =
- 答案 =
4. 公式总结
令:
则:
$$\text{答案} = \begin{cases} \max(0, n - k_1 - k_2), & \text{if } a[0] = a[n-1] \\[4pt] \max(0, n - \max(k_1, k_2)), & \text{if } a[0] \neq a[n-1] \end{cases} $$等价于:
$$\text{答案} = \max(0, \; n - \big( \text{如果 } a[0]=a[n-1] \text{ 则 } k_1+k_2 \text{ 否则 } \max(k_1, k_2) \big) ) $$
5. 示例验证
例:
(只有第一个 )
(只有最后一个 )
保留 个,修改 ✅例:
(?等等,这里 ,相等)
等一下,题目示例中第 3 个测试用例:
,相等。
保留 ,修改 ✅
6. 时间复杂度
- 计算 各需
- 总复杂度 ,对每个测试用例独立,满足 总和
7. 代码对应关系
标程中:
i1即i2即res初始为 ,然后根据条件减去保留的元素数- 最后 保证非负
8. 最终答案形式
对于每个测试用例,输出:
$$\max\left(0,\; n - \begin{cases} k_1 + k_2, & a[0] = a[n-1] \\ \max(k_1, k_2), & a[0] \neq a[n-1] \end{cases}\right) $$其中 为最长相等前缀长度, 为最长相等后缀长度。
#include <iostream> #include <vector> #include <algorithm> using namespace std; void solve() { int n; cin >> n; vector<int> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } int i1 = 0, i2 = 0; while (i1 < n && a[i1] == a[0]) { i1++; } while (i2 < n && a[n - i2 - 1] == a[n - 1]) { i2++; } int res = n; if (a[0] == a[n - 1]) { res -= i1; res -= i2; } else { res -= max(i1, i2); } cout << max(0, res) << endl; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
- 1
信息
- ID
- 6410
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者