【思路要点】
- 显然最终会达到一个叶子结点,考虑枚举它,并枚举其权值 (i,j)(i,j)(i,j) 。
- 想要使得状态纳什均衡,则要求任何玩家不能够通过改变自身的决策使得自己的权值增加,即选择进入路径上任意一点的另一个子树均不能得到更大的权值。
- 则记 auxi,0/1,jaux_{i,0/1,j}auxi,0/1,j 表示 iii 子树中先 / 后手玩家任意改变自己的决策可以到达 jjj 的状态数,用动态规划优化上述枚举即可。
- 时间复杂度 O(NK2)O(NK^2)O(NK2) ,可优化至 O(NK)O(NK)O(NK) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 5005; const int MAXK = 25; const int P = 998244353; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } vector <int> a[MAXN]; int total[MAXN], dp[MAXN][MAXK][MAXK]; int n, k, depth[MAXN], aux[MAXN][2][MAXK]; void update(int &x, int y) { x += y; if (x >= P) x -= P; } void work(int pos) { if (a[pos].size() == 0) { total[pos] = k * k; for (int i = 1; i <= k; i++) aux[pos][0][i] = aux[pos][1][i] = k; for (int i = 1; i <= k; i++) for (int j = 1; j <= k; j++) dp[pos][i][j] = 1; } else { int lc = a[pos][0], rc = a[pos][1]; depth[lc] = depth[pos] + 1; depth[rc] = depth[pos] + 1; work(lc), work(rc); total[pos] = 2ll * total[lc] * total[rc] % P; if (depth[pos] & 1) { for (int i = 1; i <= k; i++) { update(aux[pos][0][i], 1ll * aux[lc][0][i] * total[rc] % P); update(aux[pos][0][i], 1ll * aux[rc][0][i] * total[lc] % P); for (int j = 1; j <= k; j++) update(aux[pos][1][max(i, j)], 2ll * aux[lc][1][i] * aux[rc][1][j] % P); } static int pre[MAXK][2]; for (int i = 1; i <= k; i++) { pre[i][0] = pre[i - 1][0]; pre[i][1] = pre[i - 1][1]; update(pre[i][0], aux[lc][1][i]); update(pre[i][1], aux[rc][1][i]); } for (int i = 1; i <= k; i++) for (int j = 1; j <= k; j++) { dp[pos][i][j] = 1ll * dp[lc][i][j] * pre[j][1] % P; update(dp[pos][i][j], 1ll * dp[rc][i][j] * pre[j][0] % P); } } else { for (int i = 1; i <= k; i++) { update(aux[pos][1][i], 1ll * aux[lc][1][i] * total[rc] % P); update(aux[pos][1][i], 1ll * aux[rc][1][i] * total[lc] % P); for (int j = 1; j <= k; j++) update(aux[pos][0][max(i, j)], 2ll * aux[lc][0][i] * aux[rc][0][j] % P); } static int pre[MAXK][2]; for (int i = 1; i <= k; i++) { pre[i][0] = pre[i - 1][0]; pre[i][1] = pre[i - 1][1]; update(pre[i][0], aux[lc][0][i]); update(pre[i][1], aux[rc][0][i]); } for (int i = 1; i <= k; i++) for (int j = 1; j <= k; j++) { dp[pos][i][j] = 1ll * dp[lc][i][j] * pre[i][1] % P; update(dp[pos][i][j], 1ll * dp[rc][i][j] * pre[i][0] % P); } } } } int main() { read(n), read(k); for (int i = 2; i <= n; i++) { int x; read(x), x++; a[x].push_back(i); } work(1); int ans = 0; for (int i = 1; i <= k; i++) for (int j = 1; j <= k; j++) update(ans, dp[1][i][j]); writeln(ans); return 0; }