A permutation of length n is an array containing each integer from 1 to n exactly once. For example, q = [4, 5, 1, 2, 3] is a permutation. For the permutation q the square of permutation is the permutation p that p[i] = q[q[i]] for each i = 1... n. For example, the square ofq = [4, 5, 1, 2, 3] is p = q2 = [2, 3, 4, 5, 1].
This problem is about the inverse operation: given the permutation p you task is to find such permutation q that q2 = p. If there are several such q find any of them.
The first line contains integer n (1 ≤ n ≤ 106) — the number of elements in permutation p.
The second line contains n distinct integers p1, p2, ..., pn (1 ≤ pi ≤ n) — the elements of permutation p.
If there is no permutation q such that q2 = p print the number "-1".
If the answer exists print it. The only line should contain n different integers qi (1 ≤ qi ≤ n) — the elements of the permutation q. If there are several solutions print any of them.
4 2 1 4 3
3 4 2 1
4 2 1 3 4
-1
5 2 3 4 5 1
4 5 1 2 3
题意:给出一个置换p,找出另一个置换q,使得q^2=p。
思路:对于置换中的奇循环,置换平方后,还是奇循环,只是元素顺序不一样;对与偶循环,平方后会分裂成两个大小相等的循环。所以对于p中的奇循环,可以直接逆推原来的奇循环(作为一种方案),对于偶循环,它必定只能是偶循环分裂,两两大小相等的偶循环组合一下即可。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<math.h>
#define maxn 1000010
using namespace std;
vector<int>sta[maxn]; //sta[i]存储p中长度为i的循环的头个元素
vector<int>g[maxn]; //头个元素为i的循环元素
int p[maxn]; //题给的置换
int q[maxn]; //结果置换(p平方根置换)
int len[maxn]; //p中每种长度的循环的个数
int id[maxn]; //记录q的一个循环中顺序的id
bool vis[maxn];
int n;
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<=n;i++)
{
sta[i].clear();
g[i].clear();
}
memset(vis,0,sizeof(vis));
memset(len,0,sizeof(len));
for(int i=1;i<=n;i++)
{
scanf("%d",&p[i]);
}
for(int i=1;i<=n;i++)
{
if(!vis[i]) //把每个循环分开
{
int l=0,x=i;
while(!vis[x])
{
g[i].push_back(x);
vis[x]=1;
x=p[x];
l++;
}
len[l]++;
sta[l].push_back(i);
}
}
memset(vis,0,sizeof(vis));
bool flag=true;
for(int i=1;i<=n;i++)
{
if(i%2) //奇循环直接求
{
for(int j=0;j<len[i];j++)
{
for(int k=0;k<i;k++)
{ //公式很巧妙
id[k*2%i]=g[sta[i][j]][k];
}
for(int k=0;k<i;k++)
{
q[id[k]]=id[(k+1)%i];
}
}
}
else
{
if(len[i]%2) //两两配对后有多余的
{
flag=false;
break;
}
else
{
int t=1;
while(len[i]>=2*t)
{
for(int j=0;j<i;j++) //两两组合
{
q[g[sta[i][2*t-2]][j]]=g[sta[i][2*t-1]][j];
q[g[sta[i][2*t-1]][j]]=g[sta[i][2*t-2]][(j+1)%i];
}
t++;
}
}
}
}
if(!flag)
{
printf("-1\n");
}
else
{
for(int i=1;i<=n;i++)
{
printf("%d ",q[i]);
}
printf("\n");
}
}
}