Codeforces 612E Square Root of Permutation 【置换群】

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.

Sample test(s)
input
4
2 1 4 3
output
3 4 2 1
input
4
2 1 3 4
output
-1
input
5
2 3 4 5 1
output
4 5 1 2 3



题意:给定一个序列q,问p*p=q(即p[p[i]] = q[i])的p序列是否存在,不存在输出-1,反之输出任意一个p序列。


思路:置换群。

一个有奇数个的元素的群经过一次映射后,是不会改变置换后元素的顺序的(这里我们把所有元素串起来看待)。

一个有偶数个的元素的群经过一次映射后,会把群均分。

(1 2 3 4 5 6 7)^2 = (1 3 5 |7|(last) 2 4 6)。

(1 2 3 4 5 6 7 8)^2 = (1 3 5 7)(2 4 6 8)。

这样每次找到一个置换群,若元素个数have为奇,那么直接找该群的解,可以推出原序列第一个元素是群里面中间的元素,因为映射一次后顺序不变,我们依次推就可以了。若元素个数have为偶,那么若存在另一个个数为have的群,将两个群合并起来找解,从第一个位置找,每找一次跟着向后变一次。


AC代码:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (1000000+10)
#define MAXM (200000+10)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
using namespace std;
struct Node{
    int val, id;
};
Node num[MAXN];
int ans[MAXN];
vector<Node> G[MAXN];
bool vis[MAXN];
int use[MAXN];
int main()
{
    int n; Ri(n);
    for(int i = 1; i <= n; i++)
        Ri(num[i].val), num[i].id = i;
    CLR(vis, false); int top = 0; CLR(use, -1); CLR(ans, -1);
    for(int i = 1; i <= n; i++)
    {
        if(vis[i]) continue; vis[i] = true;
        int next = num[i].val, now = i; int have = 1;
        G[top].clear(); G[top].push_back(num[i]);
        while(now != next)
        {
            vis[next] = true; G[top].push_back(num[next]);
            next = num[next].val; have++;
        }
        //Pi(have);
        if(have & 1)
        {
            int first = G[top][have/2].val;
            for(int j = 0; j < have; j++)
                ans[G[top][j].id] = first, first = num[first].val;
        }
        else
        {
            if(use[have] != -1)
            {
                int first = G[use[have]][0].id;
                //Pi(last); Pi(G[top][0].id);
                for(int j = 0; j < have; j++)
                    ans[G[top][j].id] = first, ans[first] = G[top][j].val, first = num[first].val;
                use[have] = -1;
            }
            else
                use[have] = top;
        }
        top++;
    }
    bool flag = true;
    for(int i = 1; i <= n; i++) if(ans[i] == -1) {flag = false; break;}
    if(!flag) Pi(-1);
    else
    {
        printf("%d", ans[1]);
        for(int i = 2; i <= n; i++)
            printf(" %d", ans[i]);
        printf("\n");
    }
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值