容易想到建图,即 $i \to a_i$。
容易发现环上的点数值相同,所以容易想到缩点。
容易发现图变成 DAG,准确地说是森林,所以容易想到拓扑。
由于 $N,M \leq 2025$,所以容易想到 $n^2$ DP,设 $dp_{i,j}$ 表示 $i$ 子树处理完,$i$ 填 $j$ 的方案数,转移是容易的。
于是这题就容易地做完了。
#include <bits/stdc++.h>
using namespace std;
const int N = 2050, M = N << 1, mod = 998244353;
int n, m, to[N];
int dfn[N], low[N], tot = 0;
int stk[N], top = 0;
bool in_stk[N];
int scc[N], cnt = 0;
struct Graph {
int h[N], e[M], ne[M], idx = 0;
void init() {
for (int i = 0; i < N; i++) h[i] = -1;
idx = 0;
}
void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
void tarjan(int u) {
dfn[u] = low[u] = ++tot;
stk[++top] = u, in_stk[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (in_stk[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
++cnt;
while (stk[top] != u) {
scc[stk[top]] = cnt;
in_stk[stk[top]] = 0;
top--;
}
scc[stk[top]] = cnt;
in_stk[stk[top]] = 0;
top--;
}
}
} G;
int h[N], e[M], ne[M], idx = 0;
int in[N], out[N];
void add(int a, int b) {
in[b]++, out[a]++;
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
queue<int> q;
long long dp[N][N], sum[N][N], ans = 0;
void topsort() {
for (int i = 1; i <= cnt; i++) {
for (int j = 1; j <= m; j++) dp[i][j] = 1, sum[i][j] = 0;
if (!in[i]) q.push(i);
}
while (q.size()) {
int u = q.front(); q.pop();
for (int j = 1; j <= m; j++) sum[u][j] = (sum[u][j - 1] + dp[u][j]) % mod;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
for (int j = 1; j <= m; j++) dp[v][j] = (dp[v][j] * sum[u][j]) % mod;
if (--in[v] == 0) q.push(v);
}
}
ans = 1ll;
for (int i = 1; i <= cnt; i++) {
if (out[i]) continue;
ans = (ans * sum[i][m]) % mod;
}
}
int main() {
G.init();
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &to[i]), G.add(i, to[i]);
for (int i = 1; i <= n; i++)
if (!dfn[i]) G.tarjan(i);
for (int i = 1; i <= cnt; i++) h[i] = -1; idx = 0;
for (int u = 1; u <= n; u++) {
int v = to[u];
if (scc[u] == scc[v]) continue;
add(scc[u], scc[v]);
}
topsort();
printf("%lld\n", ans);
return 0;
}