otyczki-algorytmiczne-2012 tas 中国剩余定理相关

版权声明:_ https://blog.csdn.net/lunch__/article/details/82807851

题意

  • 给你一个初始为 1 , 2 , . . . , n 1, 2, ..., n 的排列,一个置换 A A ,一个排列 B B ,询问是否可以通过初始序列置换到序列 B B .

首先根据相关知识可以知道一组置换是一个环

分别考虑每一个数

如果 i i b i b_i 不在一个环中,那么就肯定无解了

不然那置换次数 k k 一定满足 k = b i i ( m o d ) k = b_i到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

b 3 b_3 b 1 b 2 b_1,b_2 的一个公约数

那么当且仅当 a 1 = a 2 ( m o d   b 3 ) a_1 = a_2(mod \ b_3) 的时候

方程组才有解 这个东西我不会证明

但如果把模运算当做减法运算来理解不是很难

我们所以只要枚举约数再枚举它的倍数就好了

时间复杂度 O ( n ln n ) O(n \ln n)

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;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/82807851
今日推荐