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 昆明 M.Stone Games(思维+可持久化线段树)