PROBLEM LINK:
Practice
Contest: Division 1
Contest: Division 2
Contest: Division 3
Contest: Division 4
Author: raysh07
Tester: archit
Editorialist: raysh07
DIFFICULTY:
Easy
PREREQUISITES:
None
PROBLEM:
A permutation is called sortable if it can be sorted by the following type of operation: Choose P_X = X and then shuffle either P[1, X] or P[X, N] arbitrarily.
You are given a permutation P. Find the minimum number of swaps (not necessarily adjacent) that you need to do to make it un-sortable.
EXPLANATION:
Let us first figure out what permutations are sortable. Intuitively, having many fixed points makes it likely for a permutation to be sortable. Let us verify that claim. Here, a fixed point is a position X such that P_X = X.
Claim: Any permutation having \ge 2 fixed points is sortable.
Proof: Suppose X and Y (X < Y) are 2 fixed points. Let Z be the position of 1. If Z < Y, then we can simply put Z into the 1-st index by an operation on [1, Z] and then use index 1 to sort everyone.
Assume Z > Y now. Then, we can use an operation on [X, N] whose only purpose will be to swap P_X and P_Z. This makes the position of 1 become X. Now, we can simply use the operation on [1, Y] to put 1 into the 1-st index yet again.
What about permutations with \le 1 fixed point? Well, obviously for 0 fixed points, they are never sortable. What about 1 fixed point?
Suppose P_X = X and P_Y \ne Y for all Y \ne X.
Let us notice another observation. Suppose Y < X and P_Y < Y, then also we can sort the permutation because operating on [1, X], we just bring Y to it’s correct place making only one necessary swap without changing P_X. Now, we have 2 fixed points, so it is sortable.
Similarly, Y > X and P_Y > X implies sortable as well.
Thus, for the permutation to have one fixed point and not be sortable means that for all Y < X, P_Y > X and for all Y > X, P_Y < X. This can be verified to be not only necessary, but also sufficient since no improvements are possible.
Also this means that the only time this can happen is when the number of integers < X and > X are equal, i.e. N odd and X = \frac{N + 1}{2}
Finally, for the minimum number of swaps. Let F denote the number of current fixed points. We can obtain \lceil \frac{F}{2} \rceil by swapping 2 fixed points at a time till there are 0 left.
However, sometimes \lfloor \frac{F}{2} \rfloor is possible by leaving out exactly one fixed point. As we have seen above, that is only possible when the last fixed point is \frac{N + 1}{2} (and N is odd). In this case, we can swap the other fixed points and check manually.
TIME COMPLEXITY:
\mathcal{O}(N) per testcase.
CODE:
Editorialist's Code (C++)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)1e18
mt19937_64 RNG(chrono::steady_clock::now().time_since_epoch().count());
void Solve()
{
int n; cin >> n;
vector <int> p(n + 1);
for (int i = 1; i <= n; i++){
cin >> p[i];
}
vector <int> fixed;
for (int i = 1; i <= n; i++){
if (p[i] == i){
fixed.push_back(i);
}
}
int m = fixed.size();
int ans = (m + 1) / 2;
if (m % 2 == 1 && n % 2 == 1 && fixed[m / 2] == (n + 1) / 2){
for (int i = 0; i < m / 2; i++){
int x = fixed[i];
int y = fixed[m - 1 - i];
swap(p[x], p[y]);
}
int pos = fixed[m / 2];
bool good = true;
for (int i = 1; i < pos; i++){
if (p[i] < pos){
good = false;
}
}
for (int i = pos + 1; i <= n; i++){
if (p[i] > pos){
good = false;
}
}
if (good){
ans = m / 2;
}
}
cout << ans << "\n";
}
int32_t main()
{
auto begin = std::chrono::high_resolution_clock::now();
ios_base::sync_with_stdio(0);
cin.tie(0);
int t = 1;
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
cin >> t;
for(int i = 1; i <= t; i++)
{
//cout << "Case #" << i << ": ";
Solve();
}
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin);
cerr << "Time measured: " << elapsed.count() * 1e-9 << " seconds.\n";
return 0;
}```