题意
- 给你一个初始为 1 , 2 , . . . , n 1, 2, ..., n 1,2,...,n的排列,一个置换 A A A,一个排列 B B B,询问是否可以通过初始序列置换到序列 B B B.
首先根据相关知识可以知道一组置换是一个环
分别考虑每一个数
如果 i i i和 b i b_i bi不在一个环中,那么就肯定无解了
不然那置换次数 k k k一定满足 k = b i 到 i 的 变 换 步 数 ( m o d 环 的 大 小 ) k = b_i到i的变换步数(mod环的大小) k=bi到i的变换步数(mod环的大小)
这样子列出了很多个方程 那我们接下来就是判断方程是否有解的问题
对于两个方程 x = a 1 m o d b 1 , x = a 2 m o d b 2 x = a_1 \ mod \ b_1, x = a_2 \ mod \ b_2 x=a1 mod b1,x=a2 mod b2
设 b 3 b_3 b3为 b 1 , b 2 b_1,b_2 b1,b2的一个公约数
那么当且仅当 a 1 = a 2 ( m o d b 3 ) a_1 = a_2(mod \ b_3) a1=a2(mod b3)的时候
方程组才有解 这个东西我不会证明
但如果把模运算当做减法运算来理解不是很难
我们所以只要枚举约数再枚举它的倍数就好了
时间复杂度 O ( n ln n ) O(n \ln n) O(nlnn)
Codes
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, a[N], b[N], size[N], dep[N], be[N], val[N];
void dfs(int x, int fa) {
++ size[fa], be[x] = fa;
if(!dep[a[x]]) {
dep[a[x]] = dep[x] + 1;
dfs(a[x], fa);
}
}
void Init() {
for(int i = 1; i <= n; ++ i)
scanf("%d", &a[i]), size[i] = 0, val[i] = -1;;
for(int i = 1; i <= n; ++ i)
scanf("%d", &b[i]), dep[i] = 0;
for(int i = 1; i <= n; ++ i)
if(!dep[i])
dep[i] = 1, dfs(i, i);
}
void Solve() {
for(int i = 1; i <= n; ++ i) {
if(be[i] != be[b[i]]) return void(puts("Forever"));
int now = be[i], tmp = dep[i] - dep[b[i]];
if(tmp <= 0) tmp += size[now];
if(val[size[now]] == -1) val[size[now]] = tmp;
else if(val[size[now]] != tmp) return void(puts("Forever"));
}
for(int i = 1; i <= n; ++ i) {
int now = -1, tmp;
for(int j = i; j <= n; j += i) {
if(val[j] == -1) continue;
tmp = val[j] % i;
if(now == -1) now = tmp;
else if(now != tmp) return void(puts("Forever"));
}
}
puts("Ever");
}
int main() {
#ifdef ylsakioi
freopen("ever.in", "r", stdin);
freopen("ever.out", "w", stdout);
#endif
while(scanf("%d", &n) != EOF)
Init(), Solve();
return 0;
}