【题解】LuoGu5151:HKE与他的小朋友

版权声明:Fashion Education https://blog.csdn.net/ModestCoder_/article/details/86774484

原题传送门
题目描述
现在有n个座位编号为11至nn,这些小朋友也编号11至nn。一开始所有小朋友都坐在相应的座位上。HKE的游戏可用一个n的排列A(A_1,A_2\cdots A_nA(A
1
​ ,A
2
​ ⋯A
n
​ )表示。一轮游戏时,对于所有的1\leq i\leq n1≤i≤n,坐在位置ii上的小朋友坐到位置A_iA
i
​ 上。

现在游戏进行了kk轮,HKE想知道游戏结束后,位置1,2\cdots n1,2⋯n分别坐了几号小朋友?

输入输出格式
输入格式:
第一行n,kn,k。

第二行A_1,A_2\cdots A_nA
1
​ ,A
2
​ ⋯A
n

输出格式:
一行n个数表示位置1,2……n1,2……n上的小朋友的编号
输入样例#1:
5 5
2 3 1 5 4
输出样例#1:
2 3 1 5 4
输入样例#2:
5 4
2 3 1 5 4
输出样例#2:
3 1 2 4 5
说明
30%的数据, n 1000 k 1000 n\leq1000,k\leq1000
100%的数据, n 100000 k 2 31 1 n\leq100000,k\leq2^{31}-1

正解是倍增,复杂度 O ( n l o g k ) O(nlogk) ,这里有一种朴素的 O ( n ) O(n) 做法
用基本的图论做法,找环,并同时计算出环的长度
然后按环,一个环一个环的处理,每个环中的元素往后一起移 k m o d k mod 环长度 个位子,所以这样能做到每个点只走一遍

Code:

/*
5 5
2 3 1 5 4
*/
#include <bits/stdc++.h>
#define res register int
#define ll long long
#define maxn 100010
using namespace std;
int n, m, a[maxn], loop[maxn], print[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	while (c < '0' || c > '9'){
		if (c == '-') w = -1; c = getchar();
	}
	while (c >= '0' && c <= '9') s = (s << 1) + (s << 3) + (c ^ 48), c = getchar();
	return s * w;
}

inline int calc(int u, int s){
	loop[u] = s;
	if (loop[a[u]]) return s;
	loop[u] = calc(a[u], s + 1);
	return loop[u];
}

int main(){
	n = read(), m = read();
	for (res i = 1; i <= n; ++ i) a[i] = read();
	for (res i = 1; i <= n; ++ i) if (!loop[i]) loop[i] = calc(i, 0);
	for (res i = 1; i <= n; ++ i)
		if (!print[i]){
			int u = i, v = i; 
			for (ll k = m % loop[i]; k; -- k) v = a[v];
			while (!print[v]){
				print[v] = u; u = a[u]; v = a[v];
			}
		}
	for (res i = 1; i <= n; ++ i) printf("%d ", print[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/86774484