---
# System prepended metadata

title: CF 1772 D. Absolute Sorting
tags: [每日CF梗題挑戰]

---

# CF 1772 D. Absolute Sorting

:::info
[Link](https://codeforces.com/contest/1772/problem/D)
:::

:::spoiler 目錄
[toc]
:::

## 題意

給定一個有$n$個數的數列$a$，請找出一個$x$，使數列$b=[\forall i\in a, \vert i-x\vert]$為一個升序排序的數列。

## 官解

### 思路

對於數列$a$，升序表示$a_1\le a_2\le\cdots \le a_n$，現在假設經過題目的操作後，$x$可以讓$a$被升序排序。

由此可知我們的目標是使關係式$\vert a_i-x\vert\le\vert a_{i+1}-x\vert$成立，這時因為絕對值很難處理，所以要分case解決。
因此將$a_i$和$a_{i+1}$的關係分成以下三種：

1. $a_i=a_{i+1}$
    $\vert a_i-x\vert\le\vert a_{i+1}-x\vert\\\Rightarrow \vert a_i-x\vert\le\vert a_i-x\vert$
    可以看出$x$不管是多少該式都會成立
2. $a_i<a_{i+1}$
    $\vert a_i-x\vert\le\vert a_{i+1}-x\vert$
    可以分開考慮$x$的三種範圍是否滿足關係式
    1. $x\le a_i$
        $$
        \vert a_i-x\vert\le\vert a_{i+1}-x\vert\\
        \Rightarrow a_i - x\le a_{i+1} - x\\
        \Rightarrow a_i\le a_{i + 1}
        $$
        此範圍滿足
    2. $x\ge a_{i+1}$
        $$
        \vert a_i-x\vert\le\vert a_{i+1}-x\vert\\
        \Rightarrow x - a_i\le x - a_{i+1}\\
        \Rightarrow a_{i+1}\le a_i
        $$
        結果與前提矛盾，該式不成立
    3. $a_i < x < a_{i + 1}$
        $$
        \vert a_i-x\vert\le\vert a_{i+1}-x\vert\\
        \Rightarrow x-a_i\le a_{i+1}-x\\
        \Rightarrow 2x\le a_i+a_{i+1}\\
        \Rightarrow x\le \frac{a_i+a_{i+1}}{2}
        $$
        若$x\le \frac{a_i+a_{i+1}}{2}$，則此範圍滿足
3. $a_i>a_{i+1}$
    $\vert a_i-x\vert\le\vert a_{i+1}-x\vert$
    可以分開考慮$x$的三種範圍是否滿足關係式
    1. $x\le a_{i+1}$
        $$
        \vert a_i-x\vert\le\vert a_{i+1}-x\vert\\
        \Rightarrow a_i-x\le a_{i+1}-x\\
        \Rightarrow a_i\le a_{i+1}
        $$
        結果與前提矛盾，該式不成立
    2. $x\ge a_i$
        $$
        \vert a_i-x\vert\le\vert a_{i+1}-x\vert\\
        \Rightarrow x - a_i\le x - a_{i+1}\\
        \Rightarrow a_{i+1}\le a_i
        $$
        此範圍滿足
    3. $a_{i+1} < x < a_i$
        $$
        \vert a_i-x\vert\le\vert a_{i+1}-x\vert\\
        \Rightarrow a_i - x\le x - a_{i+1}\\
        \Rightarrow 2x\ge a_i+a_{i+1}\\
        \Rightarrow x\ge \frac{a_i+a_{i+1}}{2}
        $$
        若$x\ge \frac{a_i+a_{i+1}}{2}$，則此範圍滿足
        
所以以結論來說，若$a_i<a_{i+1}$，則$x$必須符合$x\le \frac{a_i+a_{i+1}}{2}$；若$a_i>a_{i+1}$，則$x$必須符合$x\ge \frac{a_i+a_{i+1}}{2}$；若$a_i=a_{i+1}$，則$x$無任何限制。
因為$x$為正整數，所以以上兩個條件等價於：$x\le \lfloor\frac{a_i+a_{i+1}}{2}\rfloor$、$x\ge \lceil\frac{a_i+a_{i+1}}{2}\rceil$

有了以上關係，就只要從頭到尾遍歷$a$一次，解集合即為所有相鄰兩數的$x$範圍的聯集。若集合不存在即為無解。這樣做的時間複雜度為$O{(n)}$。

### code

>> 與初見解基本上一樣，只不過我去除了一些冗句

```cpp=
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")

#include <bits/stdc++.h>

#define F first
#define S second

using namespace std;

const int SIZE = 200050;
int a[SIZE];

void solve() {
    int n;
    cin >> n;
    int prev, now;
    pair<int, int> x {0, 1000000000};
    cin >> prev;
    for (int i = 1; i < n; ++i) {
        cin >> now;
        if (prev < now) {
            x.S = min(x.S, (prev + now) / 2);
        } else if (prev > now) {
            x.F = max(x.F, (prev + now + 1) / 2);
        }
        prev = now;
    }
    
    if (x.F <= x.S) {
        cout << x.F << "\n";
    } else {
        cout << "-1\n";
    }
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
}
```

## 初見解

### 思路

>> 因為是看題解的，所以思路一樣

### code

```cpp=
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")

#include <bits/stdc++.h>

#define F first
#define S second

using namespace std;

const int SIZE = 200050;
int a[SIZE];

void solve() {
    int n;
    cin >> n;
    int prev, now;
    pair<int, int> x {0, 1000000000};
    for (int i = 0; i < n; ++i) {
        if (!i) {
            cin >> prev;
            continue;
        }
        cin >> now;
        if (prev < now) {
            x.F = max(x.F, 0);
            x.S = min(x.S, (prev + now) / 2);
        } else if (prev > now) {
            x.F = max(x.F, (prev + now + 1) / 2);
            x.S = min(x.S, 1000000000);
        }
        prev = now;
    }
    
    if (x.F <= x.S) {
        cout << x.F << "\n";
    } else {
        cout << "-1\n";
    }
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
}
```

###### tags: `每日CF梗題挑戰`