codeforces612e(置换)

E. Square Root of Permutation
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

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.

Output

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.

Examples
input
Copy
4
2 1 4 3
output
Copy
3 4 2 1
input
Copy
4
2 1 3 4
output
Copy
-1
input
Copy
5
2 3 4 5 1
output
Copy
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");
        }
    }
}


扫描二维码关注公众号,回复: 2526538 查看本文章



猜你喜欢

转载自blog.csdn.net/qq_25576697/article/details/80286869