D. Lucky Permutation

D. Lucky Permutation

You are given a permutation$^\dagger$ $p$ of length $n$.

In one operation, you can choose two indices $1 \le i < j \le n$ and swap $p_i$ with $p_j$.

Find the minimum number of operations needed to have exactly one inversion$^\ddagger$ in the permutation.

$^\dagger$ A permutation is an array consisting of $n$ distinct integers from $1$ to $n$ in arbitrary order. For example, $[2,3,1,5,4]$ is a permutation, but $[1,2,2]$ is not a permutation ($2$ appears twice in the array), and $[1,3,4]$ is also not a permutation ($n=3$ but there is $4$ in the array).

$^\ddagger$ The number of inversions of a permutation $p$ is the number of pairs of indices $(i, j)$ such that $1 \le i < j \le n$ and $p_i > p_j$.

Input

The first line contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases. The description of test cases follows.

The first line of each test case contains a single integer $n$ ($2 \le n \le 2 \cdot 10^5$).

The second line of each test case contains $n$ integers $p_1,p_2,\ldots, p_n$ ($1 \le p_i \le n$). It is guaranteed that $p$ is a permutation.

It is guaranteed that the sum of $n$ over all test cases does not exceed $2 \cdot 10^5$.

Output

For each test case output a single integer — the minimum number of operations needed to have exactly one inversion in the permutation. It can be proven that an answer always exists.

Example

input

4
2
2 1
2
1 2
4
3 4 1 2
4
2 4 3 1

output

0
1
3
1

Note

In the first test case, the permutation already satisfies the condition.

In the second test case, you can perform the operation with $(i,j)=(1,2)$, after that the permutation will be $[2,1]$ which has exactly one inversion.

In the third test case, it is not possible to satisfy the condition with less than $3$ operations. However, if we perform $3$ operations with $(i,j)$ being $(1,3)$,$(2,4)$, and $(3,4)$ in that order, the final permutation will be $[1, 2, 4, 3]$ which has exactly one inversion.

In the fourth test case, you can perform the operation with $(i,j)=(2,4)$, after that the permutation will be $[2,1,3,4]$ which has exactly one inversion.

 

解题思路

  首先由于最终的排列必须恰好存在一个逆序对,因此最终的排列就有下面这$n-1$种可能。

  • ${\color{red}{2}}, {\color{red}{1}}, 3, 4, \ldots, n - 1, n$
  • $1, {\color{red}{3}}, {\color{red}{2}}, 4, \ldots, n - 1, n$
  • $1, 2, {\color{red}{4}}, {\color{red}{3}}, \ldots, n - 1, n$

  ...

  • $1, 2, 3, 4, \ldots, {\color{red}{n}}, {\color{red}{n - 1}}$

  现在就是通过交换序列中的两个元素,使得通过最小的交换次数将原序列变成这$n-1$个序列中的其中一个。

  由于是交换任意两个元素且求最小交换次数,因此容易联想到置换群。

  这里简单说一下置换群,对于原序列$p$,对每一个下标$i$连一条有向边$i \rightarrow p_i$,那么就会建立一个由若干个环构成的图,这就叫做置换群。如果交换的两个元素在同一个环中,那么这个环就会裂开成两个环。如果交换的两个元素不在同一个环中,那么这两个环就和合并成一个环。可以通过并查集来求得原序列有多少个环(也就是求有多少个连通块)。

  很明显,一个长度为$n$的升序排列就构成了$n$个环,假设一开始原序列有$\text{cnt}$个环,由于要将原序列变成升序的排列,因此需要将$\text{cnt}$个环裂成$n$个环,由于每次交换最多可以将一个环裂开成两个,因此至少需要交换$n - \text{cnt}$次。

  因此一种方案是先将原序列变成升序的排列,然后再交换任意两个相邻的元素一次,就得到满足题目要求的排列,交换次数是$n - \text{cnt} + 1$,但这不一定是最优解。

  其实可以发现最终的序列有$n-1$个环,并且其中一个环的大小为$2$,环中的两个元素相差恰好为$1$。因此如果原序列的某个环本来就存在两个差值为$1$的元素,那么就直接把这两个元素保留在环中,那么最后最小的交换次数就是$n - \text{cnt} - 1$。而如果原序列的每个环都不存在两个差值为$1$的元素,那么在变成升序序列后还要交换两个相邻元素,答案就是$n - \text{cnt} + 1$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 2e5 + 10;
 7 
 8 int a[N];
 9 int fa[N];
10 
11 int find(int x) {
12     return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
13 }
14 
15 void solve() {
16     int n;
17     scanf("%d", &n);
18     for (int i = 1; i <= n; i++) {
19         scanf("%d", a + i);
20         fa[i] = i;
21     }
22     int cnt = n;    // 一开始有n个环
23     for (int i = 1; i <= n; i++) {
24         int x = find(i), y = find(a[i]);    // i -> a[i]
25         if (x != y) {
26             fa[x] = y;
27             cnt--;  // 合并,环少了一个
28         }
29     }
30     for (int i = 1; i < n; i++) {
31         if (find(i) == find(i + 1)) {   // 两个相邻的元素在同一个环中
32             printf("%d\n", n - cnt - 1);
33             return;
34         }
35     }
36     printf("%d\n", n - cnt + 1);
37 }
38 
39 int main() {
40     int t;
41     scanf("%d", &t);
42     while (t--) {
43         solve();
44     }
45     
46     return 0;
47 }

 

参考资料

  Codeforces Round #842 (Div. 2) Editorial:https://codeforces.com/blog/entry/110901

  Codeforces Round #842 (Div. 2) D(置换环):https://zhuanlan.zhihu.com/p/596949353

posted @ 2023-02-09 19:13  onlyblues  阅读(33)  评论(0编辑  收藏  举报
Web Analytics