专栏文章
题解:CF252B Unsorting Array
CF252B题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minz2b22
- 此快照首次捕获于
- 2025/12/02 10:41 3 个月前
- 此快照最后确认于
- 2025/12/02 10:41 3 个月前
题目大意
给定一个长度为 的整数数组 ,需要找到两个值不相等的元素进行交换,使得交换后的数组变为“未排序”状态。
一个数组被称为“已排序”,当且仅当它满足以下两个条件之一:
- 非递减:
- 非递增:
若存在这样的交换,输出任意一对交换位置的下标(1-based);否则,输出
-1。思路分析
核心思想:局部不排序则全局不排序。
要使整个数组未排序,我们只需在数组中制造一个“瑕疵”即可,而一个长度为 的序列是判断“未排序”的最短单元。
基于这个观察,我们的核心策略是:寻找一次交换,使得数组中某个局部的三元组变得未排序,从而使整个数组未排序。
第一步
我们首先排除几种必定无解的情况:
- 当 时,数组长度过短。长度为 的数组无法交换;长度为 的数组 交换后变为 ,两者都必然是“已排序”的。
- 当数组中所有元素都相等时,根据题意无法找到两个值不相等的元素进行交换。
第二步
在排除了上述无解情况后(此时保证 且数组中至少有两种不同元素),我们遍历数组中所有连续的三元组 。
对于每一个三元组,我们尝试对其内部的两个不同元素进行交换,然后检查交换后的新三元组是否为“未排序”状态。例如,尝试交换 和 ,如果 ,就检查新三元组 是否未排序。如果是,我们便找到了解,输出 和 即可。对其他可能的内部交换(如 )也执行类似操作。
第三步
如果扫描完所有三元组后,仍然没有找到解,这意味着什么?
如果三元组扫描循环结束而未找到解,那么该数组必然是由两个不同的值 和 交替构成的序列(形如 )。
证明如下:
- 前提条件:由于上一步的扫描未找到解,我们知道在中的任意三元组 ,对其内部任意两个值不同的元素进行交换,新三元组都是“已排序”的。
1. 任意连续三元组最多只含两种不同值。
我们采用反证法。假设存在一个三元组 包含了三个不同的值。不失一般性,我们设这三个值为 ,且满足 。
一个三元组 是“未排序”的,当且仅当 或 。
我们来检验这三个值的所有 种排列:
- 排列为 :交换前两个元素,得到 。因为 ,所以 ,该序列是未排序的。产生矛盾。
- 排列为 :交换后两个元素,得到 。因为 ,所以 ,该序列是未排序的。产生矛盾。
- 排列为 :交换前两个元素,得到 。因为 ,所以 ,该序列是未排序的。产生矛盾。
- 排列为 :交换后两个元素,得到 。因为 ,所以 ,该序列是未排序的。产生矛盾。
- 排列为 :交换第一个和第三个元素,得到 。因为 ,所以 ,该序列是未排序的。产生矛盾。
- 排列为 :交换前两个元素,得到 。因为 ,所以 ,该序列是未排序的。产生矛盾。
所有排列情况都会在某次交换后产生一个“未排序”的三元组,这与我们的前提相悖。因此,假设不成立。故,任意连续三元组最多只含两种不同值。
-
该三元组的格式必须是 。 由1可知,三元组元素来自集合 。若其为 ,交换后两个元素得到 ,是未排序的,与前提矛盾。只有当三元组为 时,交换 得到 (已排序),交换 得到 (已排序),才符合前提。因此,三元组必为 形式,即 。
-
从局部推导全局结构。 既然对所有 都有 ,那么易得 且 。由于数组元素不全相等,所以整个数组必然是 的交替序列。
基于以上证明,我们得出结论:
- 对于 :此时三元组扫描已覆盖所有情况,若仍无解,则确实无解,输出
-1。 - 对于 :如果扫描失败,数组必为 结构。在此情况下,交换前两个元素 (即 ),数组变为 ,这必然是一个未排序数组。因此,我们直接输出
1 2作为答案。
代码实现
显然,时间复杂度为。
CPP#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
static inline bool unsorted(ll x, ll y, ll z) {
bool notNonDecreasing = (x > y) || (y > z);
bool notNonIncreasing = (x < y) || (y < z);
return notNonDecreasing && notNonIncreasing;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; ++i)
cin >> a[i];
if (n <= 2) {
cout << -1 << '\n';
return 0;
}
bool allEqual = true;
for (int i = 1; i < n; ++i) {
if (a[i] != a[0]) {
allEqual = false;
break;
}
}
if (allEqual) {
cout << -1 << '\n';
return 0;
}
for (int i = 0; i + 2 < n; ++i) {
ll x = a[i], y = a[i + 1], z = a[i + 2];
if (a[i] != a[i + 1]) {
if (unsorted(y, x, z)) {
cout << (i + 1) << ' ' << (i + 2) << '\n';
return 0;
}
}
if (a[i + 1] != a[i + 2]) {
if (unsorted(x, z, y)) {
cout << (i + 2) << ' ' << (i + 3) << '\n';
return 0;
}
}
if (a[i] != a[i + 2]) {
if (unsorted(z, y, x)) {
cout << (i + 1) << ' ' << (i + 3) << '\n';
return 0;
}
}
}
if (n == 3) {
cout << -1 << '\n';
return 0;
}
if (a[0] != a[1]) {
cout << 1 << ' ' << 2 << '\n';
return 0;
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...