【题目描述】
HKE带着 n n n个小朋友做游戏
现在有 n n n个座位编号为 1 1 1至 n n n,这些小朋友也编号 1 1 1至 n n n。一开始所有小朋友都坐在相应的座位上。HKE的游戏可用一个 n n n的排列 A ( A 1 , A 2 ⋯ A n ) A(A_1,A_2\cdots A_n) A(A1,A2⋯An) 表示。一轮游戏时,对于所有的 1 ≤ i ≤ n 1\leq i\leq n 1≤i≤n坐在位置 i i i上的小朋友坐到位置 A i A_i Ai上。
现在游戏进行了 k k k轮,HKE想知道游戏结束后,位置 1 , 2 ⋯ n 1,2\cdots n 1,2⋯n分别坐了几号小朋友?
【输入描述】
第一行
n
,
k
n,k
n,k
第二行
A
(
A
1
,
A
2
⋯
A
n
)
A(A_1,A_2\cdots A_n)
A(A1,A2⋯An)
【输出描述】
一行
n
n
n个数表示位置
1
,
2
…
n
1,2…n
1,2…n上的小朋友的编号。
S a m p l e I n p u t Sample~~Input Sample Input
5 5
2 3 1 5 4
S a m p l e O u t p u t Sample~~Output Sample Output
2 3 1 5 4
【题意分析】
提供一种暴力但思维清奇的方法:
我们很容易发现,这些小朋友的操作可以用有向边来表示。
很自然地想到这些有向边会连成环,而经过k次操作后小朋友的位置会在环内不断循环。
先用tarjan进行缩点,我们可以用vector把环全部存起来,对于每个小朋友,可以通过k 对环大小取模直接找到最终位置。
时间复杂度 O ( N ) O(N) O(N) t a r j a n O ( n ) tarjanO(n) tarjanO(n)+处理答案 O ( n ) O(n) O(n)
Code :
#include <bits/stdc++.h>
#define rep(x,a,b) for (register int x = a; x <= b; x++)
#define cross(x,a) for (register int x = head[a]; x; x = edge[x].next)
#define MAXN 150000
using namespace std;
struct Front_Link_Star {
int next, to;
}edge[MAXN];
vector <int> mmp[MAXN];
//vector[x][y]是第x个环的第y个元素
int head[MAXN], dfn[MAXN], low[MAXN], stac[MAXN], DAG[MAXN];
int cnt[MAXN], ans[MAXN], a[MAXN], pos[MAXN];
int _cnt, idx, top, tot_circle, n, k;
bool vis[MAXN];
inline void connect (int u, int v) {
edge[++_cnt].to = v;
edge[_cnt].next = head[u];
head[u] = _cnt;
}
//tarjan
void tarjan (int now) {
dfn[now] = low[now] = ++idx;
vis[now] = 1; stac[++top] = now;
cross (i, now) {
int v = edge[i].to;
if (! dfn[v]) {
tarjan (v);
low[now] = min (low[now], low[v]);
}
else if (vis[v]) low[now] = min (low[now], low[v]);
}
if (dfn[now] == low[now]) {
tot_circle++;
while (int y = stac[top--]) {
DAG[y] = tot_circle;
cnt[DAG[y]]++;
vis[y] = 0;
if (now == y) break;
}
}
}
int main () {
scanf ("%d %d", &n, &k);
rep (i, 1, n) {
scanf ("%d", &a[i]); connect (i, a[i]);
}
rep (i, 1, n) if (! dfn[i]) tarjan (i);
memset (vis, 0, sizeof (vis));
rep (i, 1, n) {
int now = i;
while (! vis[now]) {
mmp[DAG[i]].push_back (now);
vis[now] = 1; now = a[now];
}
}
//用vector把环存起来
//mmp[i][j]表示第i个环第j个元素
rep (i, 1, tot_circle) {
int rest = k % cnt[i];
rep (j, 0, mmp[i].size ()-1) {
ans[mmp[i][(j+rest) % cnt[i]]] = mmp[i][j];
}
}
//k对环大小取模直接找到最终位置
rep (i, 1, n) printf ("%d ", ans[i]);
return 0;
}