CF2188 C. Restricted Sorting

题解 C. Restricted Sorting

题目位置: https://codeforces.com/contest/2188/problem/C.

现在我要认真解决每一道题目,要相信一定会有提高的.

题目描述

你有一个长度为 N N N 的序列 A A A, 现在你需要将这个序列从小到大排序.

你有一个操作:

  • 交换 A A A 数组中的两个数字,我们设交换的位置为 i , j i,j i,j, 那么你需要满足 k ≤ ∣ A i − A j ∣ k \leq |A_i-A_j| k≤∣Ai−Aj∣.

现在要求出最大的 k k k.

思路

这个真的太巧妙了!

我们设这个序列的最小值为 P P P, 最大值为 Q Q Q.

首先我们把这个数组排序,得到序列 B B B.

当 A i = B i A_i=B_i Ai=Bi 时,这个位置是不需要交换的, 因为已经到达自己的位置了.

当 A i ≠ B i A_i\neq B_i Ai=Bi 时,这个位置需要交换.

如果这个序列是递增的,也就是这个序列本身就排好序了,那么我们直接输出 − 1 -1 −1 即可.

否则, 我们来考虑什么样子的 k k k 可以满足这种条件.

  • 如果 Q − P < k Q-P<k Q−P<k, 那么也不会满足条件.
    • 原因很简单,我们发现这个序列不是升序的,那么一定要交换两个元素,观察 k ≤ ∣ A i − A j ∣ k \leq |A_i-A_j| k≤∣Ai−Aj∣, 肯定是 ∣ A i − A j ∣ |A_i-A_j| ∣Ai−Aj∣ 越大越好.
    • 什么时候 ∣ A i − A j ∣ |A_i-A_j| ∣Ai−Aj∣ 最大? 答案就是 Q − P Q-P Q−P 时候.
    • 如果在最大的情况下都无法交换,那么其他无序的也一定不能交换
  • 如果 A i ≠ B i A_i\neq B_i Ai=Bi 且 A i − P < k A_i-P<k Ai−P<k 且 Q − A i < k Q-A_i<k Q−Ai<k, 就代表着这个节点无法交换,所以 k k k 也不合法.
  • 其他的情况那么 k k k 就是合法的.

我们继续考虑合法的情况.

这里设 j j j 为 i i i 应该到达的位置.

如果 A i − P ≥ k A_i-P\geq k Ai−P≥k 且 A j − P ≥ k A_j-P\geq k Aj−P≥k.

这就代表着我们可以借助最小值,将 A i A_i Ai 换到 A j A_j Aj.

这个序列就是 { A i , A j , P } \{A_i,A_j,P\} {Ai,Aj,P}.

现在我们要将 A j A_j Aj 和 A i A_i Ai 交换

  1. 交换 A i A_i Ai 和 P P P, 得 { P , A j , A i } \{P,A_j,A_i\} {P,Aj,Ai}.
  2. 交换 A j A_j Aj 和 P P P, 得 { A j , P , A i } \{A_j,P,A_i\} {Aj,P,Ai}.
  3. 交换 A i A_i Ai 和 P P P, 得 { A j , A i , P } \{A_j,A_i,P\} {Aj,Ai,P}.

在实际的代码中并不需要写出这些东西,只需要知道贡献即可.

贡献的推导.

上面的过程是我们知道 k 时如何最优的反转 , 那么我们现在在不知道 k 的情况下怎么操作?.

我们现在要让 k k k 最大,那么可以知道 k = min ⁡ ( A i − P , A j − P ) k=\min(A_i-P,A_j-P) k=min(Ai−P,Aj−P).
如果 A i − P ≥ k A_i-P\geq k Ai−P≥k 且 Q − A j ≥ k Q-A_j\geq k Q−Aj≥k 时.

那么我们就是要同时借助最大和最小值进行移位.

这个序列就是 { A i , A j , P , Q } \{A_i,A_j,P,Q\} {Ai,Aj,P,Q}.

  1. 交换 A i A_i Ai 和 P P P, { P , A j , A i , Q } \{P,A_j,A_i,Q\} {P,Aj,Ai,Q}.
  2. 交换 Q Q Q 和 P P P, { Q , A j , A i , P } \{Q,A_j,A_i,P\} {Q,Aj,Ai,P}.
  3. 交换 A j A_j Aj 和 Q Q Q, { A j , Q , A i , P } \{A_j,Q,A_i,P\} {Aj,Q,Ai,P}.
  4. 交换 Q Q Q 和 P P P, { A j , P , A i , Q } \{A_j,P,A_i,Q\} {Aj,P,Ai,Q}.
  5. 交换 P P P 和 A i A_i Ai, { A j , A i , P , Q } \{A_j, A_i, P, Q\} {Aj,Ai,P,Q}.

这里的贡献就是 k = min ⁡ ( A i − P , Q − A j ) k=\min(A_i-P, Q-A_j) k=min(Ai−P,Q−Aj).

我们肯定要让 k k k 最大,因为 ∣ A i − A j ∣ ≥ k |A_i-A_j|\geq k ∣Ai−Aj∣≥k, 所以我们要最大化每一个点的贡献.

那么一个点的贡献就是: max ⁡ ( min ⁡ ( A i − P , A j − P ) , min ⁡ ( A i − P , Q − A j ) ) \max(\min(A_i-P,A_j-P), \min(A_i-P, Q-A_j)) max(min(Ai−P,Aj−P),min(Ai−P,Q−Aj)).

所有点的贡献就是:
a n s = min ⁡ i = 1 N ( max ⁡ ( min ⁡ ( A i − P , A j − P ) , min ⁡ ( A i − P , Q − A j ) ) ) ans=\min_{i=1}^{N}(\max(\min(A_i-P,A_j-P), \min(A_i-P, Q-A_j))) ans=i=1minN(max(min(Ai−P,Aj−P),min(Ai−P,Q−Aj)))

直接计算显然是 O ( N 2 ) O(N^2) O(N2) 的,因为要枚举每一个点及其对应点.

发现就是每一个点取 max ⁡ \max max, 然后再取 min ⁡ \min min.

所以里面的两个 min ⁡ \min min 可以作为重复部分去掉.

所以答案为 a n s = min ⁡ i = 1 N ( max ⁡ ( A i − P , Q − A i ) ) ) ans=\min_{i=1}^{N}(\max(A_i-P,Q-A_i))) ans=mini=1N(max(Ai−P,Q−Ai))).

按照这个计算即可,时间复杂度为 O ( N ) O(N) O(N).

代码

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <set>

using namespace std;

void solve();
int main()
{
    // freopen("Sample.in", "r", stdin);
    int T;
    scanf("%d", &T);
    while (T--) solve();
    return 0;
}

#define MAXN 200010
int N;

void solve() {
    scanf("%d", &N);
    vector<int> A(N);



    for (int& it : A) scanf("%d", &it);
    vector<int> B = A;
    sort(B.begin(), B.end());

    if (A == B) return printf("-1\n"), void();
    int ans = 2e9;
    for (int i = 0; i < N; i++) {
        if (A[i] == B[i]) continue;
        ans = min(ans, max(B[i] - B[0], B[N - 1] - B[i]));
    }
    printf("%d\n", ans);
}
相关推荐
We་ct2 小时前
LeetCode 54. 螺旋矩阵:两种解法吃透顺时针遍历逻辑
前端·算法·leetcode·矩阵·typescript
星火开发设计2 小时前
C++ 预处理指令:#include、#define 与条件编译
java·开发语言·c++·学习·算法·知识
许泽宇的技术分享2 小时前
第 1 章:认识 Claude Code
开发语言·人工智能·python
想放学的刺客2 小时前
单片机嵌入式试题(第27期)设计可移植、可配置的外设驱动框架的关键要点
c语言·stm32·单片机·嵌入式硬件·物联网
AIFQuant2 小时前
如何利用免费股票 API 构建量化交易策略:实战分享
开发语言·python·websocket·金融·restful
Hx_Ma162 小时前
SpringMVC返回值
java·开发语言·servlet
独自破碎E2 小时前
【滑动窗口+字符计数数组】LCR_014_字符串的排列
android·java·开发语言
mit6.8242 小时前
dijk|tire+floyd+dp %
算法
2601_949480062 小时前
【无标题】
开发语言·前端·javascript