前言
一眼倍增,但是没想到具体怎么做……
然后贺了题解,甚至没贺明白。
详见此处。
题解
建图 $i \rightarrow p_i$,会形成若干个环。
那么现在关心的问题就是每个点在环上变换 $k$ 次(不是走 $k$ 次)会到哪里。
然后手模发现,变换一次相当于走两步,变换两次相当于走四步,变换三次相当于八步……
所以是 $2^k \bmod l$,$l$ 是环长。
这个快速幂加倍增就可以解决了。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 15;
long long k;
int n, p[N];
int len[N], stk[N], top;
int nxt[N][25];
int qmi(int a, long long k, int mod) {
int res = 1;
while (k) {
if (k & 1) res = (res * 1ll * a) % mod;
a = (a * 1ll * a) % mod;
k >>= 1;
}
return res;
}
int main() {
scanf("%d%lld", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
for (int i = 1; i <= n; i++) {
if (len[i]) continue;
top = 1; stk[1] = i;
int now = p[i];
while (now != i) {
stk[++top] = now;
now = p[now];
}
for (int i = 1; i <= top; i++) len[stk[i]] = top;
}
for (int i = 1; i <= n; i++) nxt[i][0] = p[i];
for (int i = 1; i <= 20; i++)
for (int j = 1; j <= n; j++) nxt[j][i] = nxt[nxt[j][i - 1]][i - 1];
for (int i = 1; i <= n; i++) {
int c = qmi(2, k, len[i]), now = i;
for (int j = 20; j >= 0; j--) {
if (c & (1 << j)) now = nxt[now][j];
}
printf("%d ", now);
}
return 0;
}