Official

A - Reverse and Count Editorial by evima


First, a naive algorithm can be considered by actually enumerating and sorting all \(N(N+1)/2\) sequences, but the time complexity is \(\mathrm{O} (N^3 \log N)\), which results in TLE.

Let’s improve the time complexity. We will consider determining the answer from the first element.
Due to the nature of the inversion operation, the first element of \(f(L,R)\) can be divided into the following 2 cases depending on \(L\) and \(R\) (here, let \(a[n]\) be the \(n\)-th element of the sequence \(a\)):

  • If \(L = 1\) and \(R \neq 1\): \(f(L, R)[1] = A_R\).
  • In all other cases: \(f(L, R)[1] = A_1\).

Let’s focus on the relationship between \(A_R\) and \(A_1\). Among \(A_1, A_2, A_3, \dots, A_N\), let there be \(x\) elements less than \(A_1\) and \(y\) elements greater than \(A_1\). Then, using appropriate sequences \(s_1, \dots, s_x, t_1, \dots, t_y\), we can represent it as

\[ A_{s_1} \lt A_{s_2} \lt \dots \lt A_{s_x} \lt A_1 \lt A_{t_1} \lt A_{t_2} \lt \dots \lt A_{t_y}. \]

(Note that since \(A\) is a permutation, all elements are distinct, so the terms are connected by \(\lt\).) From here, when comparing the first elements of the possible \(f(L, R)\), we get the following equation:

\[ \begin{aligned} &f(1, s_1)[1] \lt f(1, s_2)[1] \lt \dots \lt f(1, s_x)[1] \\ &\lt (\text{other sequences})[1] \\ &\lt f(1, t_1)[1] \lt f(1, t_2)[1] \lt \dots \lt f(1, t_y)[1] \end{aligned} \]

From this equation, the \(x\) smallest and \(y\) largest of the \(f(L, R)\) columns can be calculated by finding \(s_1, \dots, s_x\) or \(t_1, \dots, t_y\). Therefore, if \(K\) is in the range of either one, we can find the corresponding pair of \(L, R\).

Let’s consider the case where the first element of the desired \(f(L, R)\) matches \(A_1\). If we only look at \(f(L, R)\) with the first element being \(A_1\), we can focus on the second element and consider the relationship between \(A_2\) and \(A_3, \dots, A_N\) to identify some number of top and bottom permutations.
By repeating this process for the second element, third element, \(\dots\), \(N\)-th element, we can detect the answer for the case where the \(K\)-th sequence does not match \(A\).
If the \(K\)-th permutation matches \(A\), we cannot find the pair of \(L, R\) until the end by examining up to the \(N\)-th element using this method. In this case, the answer completely matches \(A\), so we output \(A\) as it is.
The overall time complexity is \(\mathrm{O}(N^2)\), which is sufficiently fast.

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() {
  int N, K;
  cin >> N >> K;
  vector<int> A(N);
  for (auto& x : A) cin >> x;

  int a = 1, b = N * (N + 1) / 2;
  for (int i = 0; i < N; i++) {
    vector<int> small, large;
    for (int j = i + 1; j < N; j++) {
      if (A[j] < A[i]) small.push_back(A[j]);
      if (A[j] > A[i]) large.push_back(A[j]);
    }
    int x = -1;
    if (K - a < int(small.size())) {
      sort(begin(small), end(small));
      x = small[K - a];
    }
    if (b - K < int(large.size())) {
      sort(begin(large), end(large));
      reverse(begin(large), end(large));
      x = large[b - K];
    }
    if (x != -1) {
      int j = i;
      while (A[j] != x) j++;
      reverse(begin(A) + i, begin(A) + j + 1);
      break;
    }
    a += small.size();
    b -= large.size();
  }
  for (int i = 0; i < N; i++) cout << A[i] << " \n"[i + 1 == N];
}

posted:
last update: