您的位置:首页 > 其它

Educational Codeforces Round 4 E. Square Root of Permutation(置换、构造)

2016-02-11 14:53 471 查看
题意:

给定N≤106的置换q,现要找到一个p2=q,多解输出任意一个,无解输出−1

p2=q即是q[i]=p[p[i]]

分析:

计算样例可以发现,置换的奇循环平方后循环长度不变,而偶循环则分解为2个相同长度的循环

我们用()表示一个循环,即(a1a2a3)指的是a1→a2→a3→a1

则规律表示如下:

奇:(a1a2a3a4a5a6a7)2=(a1a3a5a7a2a4a6)

偶:(a1a2a3a4a5a6)2=(a1a3a5)(a2a4a6)

偶数规律显然,奇数的话,如果是0based下标的话id[2∗i%sz]=a[i]

得到原始置换后,我们就可以还原序列了

关于−1的情况,构造的话,显然奇数可以长度不变也可以合并,偶数只能合并

构造则选择,奇数不变,偶数每两个合并,如果存在偶数不能合并即不能构造

规律还可以推广,对于Ak=B的情况,循环长度能被k整数的只能分裂成k份,不能整数的则长度不变

构造法类同于k=2:

k∤sz:=id[k∗i%sz]=a[i]

k | sz:=id[idx++]=a[i]

代码:

//
//  Created by TaoSama on 2016-02-11
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n, a
;
int vis
, id
, ans
;
vector<int> cycle
;

bool cmp(const vector<int>& x, const vector<int>& y) {
return x.size() < y.size();
}

int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);

while(scanf("%d", &n) == 1) {
for(int i = 1; i <= n; ++i) scanf("%d", a + i);
int cnt = 0;
memset(vis, false, sizeof vis);
for(int i = 1; i <= n; ++i) {
if(vis[i]) continue;
int tmp = i;
cycle[++cnt].clear();
do {
vis[tmp] = 1;
cycle[cnt].push_back(tmp);
tmp = a[tmp];
} while(tmp != i);
}
sort(cycle + 1, cycle + 1 + cnt, cmp);

bool ok = true;
for(int i = 1; i <= cnt; ++i) {
int sz = cycle[i].size();
if(sz & 1) {
for(int j = 0; j < sz; ++j)
id[2 * j % sz] = cycle[i][j];
for(int j = 0; j < sz; ++j)
ans[id[j]] = id[(j + 1) % sz];
} else if(i + 1 <= cnt && cycle[i + 1].size() == sz) {
for(int j = 0, k = 0; j < sz; ++j) {
id[k++] = cycle[i][j];
id[k++] = cycle[i + 1][j];
}
sz <<= 1;
for(int j = 0; j < sz; ++j)
ans[id[j]] = id[(j + 1) % sz];
++i;
} else {
ok = false;
break;
}
}
if(!ok) puts("-1");
else {
for(int i = 1; i <= n; ++i)
printf("%d%c", ans[i], " \n"[i == n]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  置换 构造