2021 第45届icpc昆明站 J题 Parallel Sort 题解

题目(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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值