题目(Problem):
题目大意(The meaning fo the problem):
给出一个组全排列数字,每次操作可以对排列中任意两个数交换,要求每次交换不重复使用某一个数字。输出需要的次数和每次的操作。
题目思路(The method of solving):
构建环。对于a[i]找到a[a[i]]连环,由于是全排列最后一次肯定找到第一个a[i]
对于某一个环,最多只需要两次操作。所以操作只有可能是0,1,2次。
对于一个长度大于2的环,将环拆分成n/2个只有2个点的环,最后再执行一次交换则变为有序。
代码(Code):
#include "bits/stdc++.h"
#define endl "\n"
using namespace std;
const int MAXN = 1e5 + 5;
int a[MAXN];
vector<int>ans, ans2;
bool flag[MAXN] = {0};
int main(void) {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
for (int i = 1; i <= n; ++i) {
if (a[i] != i) break;
if (i == n) {
cout << 0 << endl;
return 0;
}
}
bool isOne = true;
for (int i = 1; i <= n; ++i) {
if (flag[i]) continue;
int x = i;
vector<int>temp;
while (!flag[x]) {
temp.push_back(x);
flag[x] = true;
x = a[x];
}
//cout << temp.size() << ' ' << temp[0] << endl;
if (temp.size() == 2) {
ans.push_back(temp[0]);
ans.push_back(temp[1]);
}else {
for (int l = 1, r = temp.size() - 1; l < r; l++, r--) {
ans.push_back(temp[l]);
ans.push_back(temp[r]);
swap(temp[l], temp[r]);
}
for (int l = 0, r = temp.size() - 1; l < r; l++, r--) {
ans2.push_back(temp[l]);
ans2.push_back(temp[r]);
}
isOne = false;
}
}
if (isOne) {
cout << 1 << endl;
}else {
cout << 2 << endl;
}
cout << ans.size() / 2;
for (auto it : ans) {
cout << ' ' << it;
}
cout << endl;
if (!isOne) {
cout << ans2.size() / 2;
for (auto it : ans2) {
cout << ' ' << it;
}
cout << endl;
}
return 0;
}