AI Translated from Chinese

Problem

D. Flipper

Problem: Given an n-permutation p[], select an interval [l, r] (l <= r), construct a new permutation: a[r+1:] + a[l:r].reverse() + a[1:l] (using Python slice notation, i.e., left-closed right-open interval). Find the lexicographically largest permutation that can be constructed.

Analysis

Assume the answer is represented by $ ans_i $.

Initial analysis: when $ r = n $, $ ans_1 = r_n $, otherwise $ ans_1 = r_{n+1} $. To ensure lexicographic maximum, we need to select the largest possible $ r $.

It’s easy to know that when $ p_1 = n $, $ r $ should be $ n-1 $, otherwise select $ n $.

After determining $ r $, look at $ l $. There’s a trick: first output a[r+1:] + a[r], then traverse from a[r-1] backward. As long as a[i] < a[1] (indicating that if $ l $ is chosen as $ i $, the operation would make the lexicographic order smaller, so $ l $ is chosen as $ i+1 $), immediately output a[1:i+1] (note this is still a left-closed right-open interval).

This is the CF editorial solution:

In these constraints we could solve the problem for $ O(n^2) $. Let us note that there can be no more than two candidates for the value $r$. Since the first number in the permutation will be either $p_r+1$ if $r<n$, or $p_r$ if $r=n$. Then let’s go through the value of $r$ and choose the one in which the first number in the resulting permutation is as large as possible. Next, if $p_n=n$, then we can have two candidates for $r$ is $n$,$n−1$, but note that it is always advantageous to put $r=n$ in that case, since it will not spoil the answer. Then we can go through $l$, and get the solution by the square, but we can do something smarter.

Notice now that the answer already contains all the numbers $p_i$ where $i>r$. And then we write $p_r$, $p_r−1$, …, $p_l$ where $l$ is still unknown, and then $p_1$, $p_2$, …, $p_l−1$. In that case, let’s write pr as $l≤r$ and then write $p_r−1$, $p_r−2$, … as long as they are larger than $p_1$. Otherwise, we immediately determine the value of $l$ and finish the answer to the end. Thus, constructively we construct the maximal permutation.

Code

#include <bits/stdc++.h>

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _all(x) (x).begin(), (x).end()
#define _abs(x) ((x >= 0) ? (x) : (-x))
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define PDD pair<double, double>
#define fi first
#define se second

typedef long long LL;
typedef long double LD;
typedef unsigned long long ULL;

const int INF = 0x3f3f3f3f;
const LL LINF = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0);

using namespace std;

const int N = 2000 + 20;
int n, a[N];


void init() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
}

void solve() {
    int r = 1;
    // choose r, i.e. find the largest num in a[1:n] and record its index
    // if a[i] == n, choose a[r] == n-1
    // else a[r] == n
    for (int i = 1; i <= n; i++) {
        if (a[min(n, r+1)] <= a[min(n, i+1)]) r = i;
    }

    // cout << a[r+1:]
    for (int i = r+1; i <= n; i++) cout << a[i] << ' ';

    cout << a[r] << ' ';

    // cout << a[r-1]..a[l] << a[1:l]
    for (int i = r-1; i > 0; i--) {
        if (a[i] > a[1]) {
            cout << a[i] << ' ';
        }
        // find l: l = i-1
        else {
            for (int j = 1; j <= i; j++) {
                cout << a[j] << ' ';
            }
            break;
        }
    }
    cout << "\n";
}

int main() {
    IOS
    int test_case;
    cin >> test_case;
    while (test_case--) {
        init();
        solve();
    }
    return 0;
}

The CF editorial solution is brilliant:

int r = 1;
for (int i = 1; i <= n; i++) {
    if (a[min(n, r+1)] <= a[min(n, i+1)]) r = i;
}

Equivalent to:

int r = 1;
if (a[1] == n) {
    if (a[n] == n-1) {
        r = n;
    }
    else for (int i = 2; i <= n; i++) {
        if (a[i] == n-1) {
            r = i-1;
            break;
        }
    }
}
else {
    if (a[n] == n) {
        r = n;
    }
    else for (int i = 1; i <= n; i++) {
        if (a[i] == n) {
            r = i-1;
            break;
        }
    }
}

Elegantly compressed my dozen lines of code at the time into just two or three lines.

How beautiful

Summary

I was stuck on this problem at the time. After finding $ r $, I didn’t know how to proceed. Actually, just need to slightly change the way of thinking, think in reverse ( ̄▽ ̄)