2020ICPC昆明 J.Parallel Sort(思维,规律)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020ICPC昆明 J.Parallel Sort(思维,规律)相关的知识,希望对你有一定的参考价值。

题意
在这里插入图片描述


①.若原数组本就是有序的,无需操作

②.若操作次数为一,我们可以验证。

每次遇到 i ! = p i i!=p_i i!=pi时都交换 i i i位置和 p i p_i pi位置,最后检查是否有序

③.否则,可以证明,一定可以在两步之内完成排序

举个例子

6

5 4 3 6 2 1

因为 p 1 = 5 p_1=5 p1=5,所以一定存在一步操作是交换位置 1 1 1和位置 5 5 5

然而 p 5 ! = 1 p_5!=1 p5!=1,所以我们应该合理构造使得 p 5 = 1 p_5=1 p5=1

于是我们交换位置 ( 5 , 6 ) (5,6) (5,6)

得到序列5 4 3 6 1 2

现在数字 1 , 5 1,5 1,5得到满足,然而数字 2 2 2还不满足

又因为 p 6 = 2 p_6=2 p6=2,所以一定存在一步操作是交换位置 6 6 6和位置 2 2 2

然而 p 2 ! = 6 p_2!=6 p2!=6,所以我们应该构造使得 p 2 = 6 p_2=6 p2=6

于是我们交换位置 ( 2 , 4 ) (2,4) (2,4)

得到序列5 6 3 4 1 2

现在数字 2 , 6 2,6 2,6得到满足,检查数字 4 4 4是否满足要求

发现已经在正确的位置了,所以终止

至此第一次操作结束,第二次操作直接暴力调换就行了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int n,p[maxn],pos[maxn],vis[maxn],a[maxn];
typedef pair<int,int>w;
vector<w>vec1,vec2;
void zero()
{
	int flag = 1;
	for(int i=1;i<=n;i++)
		if( i!=p[i] )	flag = 0;
	if( flag ){ printf("0"); exit(0); }
}
void one()
{
	for(int i=1;i<=n;i++)	a[i] = p[i];
	for(int i=1;i<=n;i++)
	{
		if( i==a[i] )	continue;
		//i和a[i]换位置
		if( vis[i] || vis[a[i]] )	continue;
		vis[i] = vis[a[i]] = 1;
		vec1.push_back( w(i,a[i]) );
		swap( a[i],a[a[i]] ); 
	}
	int flag = 1;
	for(int i=1;i<=n;i++)
		if( i!=a[i] )	flag = 0;
	if( flag )
	{
		printf("1\\n%d ",vec1.size() );
		for(int i=0;i<vec1.size();i++)
		{	
			printf("%d %d",vec1[i].first,vec1[i].second );
			if( i!=vec1.size()-1 )	printf(" ");
		}
		exit(0);
	}
	memset( vis,0,sizeof vis );
	vec1.clear();
}
void two()
{
	for(int i=1;i<=n;i++)
	{
		if( p[i]==i || vis[i] )	continue;
		int now = i;//当前考虑now位置和p[now]位置交换 
		while( true )
		{
			int id = p[now], ned = now;//id位置需要换成数字ned
			int l = p[id], r = ned;
			if( l==r )	break;
			vis[id] = vis[pos[ned]] = 1;
			vec1.push_back( w(id,pos[ned] ) ); 
			swap( p[id],p[pos[ned]] );				swap( pos[l],pos[r] );
			now = pos[l];
		}
	}
	for(int i=1;i<=n;i++)
	{
		if( p[i]==i )	continue;
		vec2.push_back( w(i,p[i]) );
		swap( p[i],p[p[i]] );
	}
	cout << 2 << endl << vec1.size() << " ";
	for(int i=0;i<vec1.size();i++)
	{	
		printf("%d %d",vec1[i].first,vec1[i].second );
		if( i!=vec1.size()-1 )	printf(" ");
		else	printf("\\n");
	}
	cout << vec2.size() << " ";
	for(int i=0;i<vec2.size();i++)
	{	
		printf("%d %d",vec2[i].first,vec2[i].second );
		if( i!=vec2.size()-1 )	printf(" ");
	}
}
int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)	cin >> p[i],pos[p[i]] = i;
	zero(); one(); two();
}

另一种解法是考虑环

别人的解析

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1e6 + 5;
int n;
int p[N];
int v[N];
signed main()
{
    ios::sync_with_stdio(false);

    cin >> n;
    vector<int> ans[2];
    for (int i = 1; i <= n; i++)
        cin >> p[i];
    for (int _ = 0; _ < 2; _++)
    {
        memset(v, 0, sizeof v);
        for (int i = 1; i <= n; i++)
        {
            if (v[i])
                continue;
            if (i == p[i])
                continue;
            int t = p[i];
            vector<int> cyc;
            cyc.push_back(i);
            v[i] = 1;
            while (t != i)
                cyc.push_back(t), v[t] = 1, t = p[t];
            for (int j = 0; j < cyc.size() / 2; j++)
            {
                int x = cyc[j], y = cyc[cyc.size() - 1 - j];
                ans[_].push_back(x);
                ans[_].push_back(y);
                swap(p[x], p[y]);
            }
        }
    }
    if (ans[0].size() == 0)
    {
        cout << 0 << endl;
    }
    else if (ans[1].size() == 0)
    {
        cout << 1 << endl;
        cout << ans[0].size() / 2 << " ";
        for (auto i : ans[0])
            cout << i << " ";
        cout << endl;
    }
    else
    {
        cout << 2 << endl;
        cout << ans[0].size() / 2 << " ";
        for (auto i : ans[0])
            cout << i << " ";
        cout << endl;
        cout << ans[1].size() / 2 << " ";
        for (auto i : ans[1])
            cout << i << " ";
        cout << endl;
    }
}

以上是关于2020ICPC昆明 J.Parallel Sort(思维,规律)的主要内容,如果未能解决你的问题,请参考以下文章

2020ICPC昆明 C.Cities(区间dp)

2020ICPC 昆明 M.Stone Games(思维+可持久化线段树)

2020ICPC昆明 L.Simone and graph coloring(思维+nlog(n)的最长下降子序列)

ACM周赛&ICPC昆明资格赛

ICPC20昆明M——动态开点权值线段树(主席树)

2021 ICPC昆明 Stone Games(主席树)