考虑设 \(f_{i,j}\) 表示现在存活 \(i\) 个人,血量最大的人为 \(j\)。这么设是因为注意到有没有胜者其实之和血量最大的是谁,以及有多少个血量最大的有关。
边界情况 \(f_{1,i}=0\)。
考虑转移。如果 \(j<i\),则所有人都会在下一轮死掉,就没有胜者,所以此时 \(f_{i,j}\) 就是所有合法的情况总数,也就是 \(j^i-(j-1)^i\),即值域 \([1,j]\) 序列个数减 \([1,j-1]\) 序列个数。
如果 \(j\ge i\),则我们枚举这一轮过去后死了 \(0\le k\le i\) 个人,选这 \(k\) 个人有 \(i \choose k\) 种选法,他们要死掉所以他们的血量一定要在 \([1,i-1]\) 之间,一共有 \((i-1)^k\) 种合法状态,最后乘上 \(f_{i-k,j-(i-1)}\)。
时间复杂度 \(O(n^3)\),但是跑不太满。
const int MAXN = 505, mod = 998244353;
int n, x, C[MAXN][MAXN], f[MAXN][MAXN];int quickpow(int a, int b) {int ret = 1;while (b) {if (b & 1) ret = ret * a % mod;a = a * a % mod; b >>= 1;}return ret;
}int add(int x, int y) {x += y;if (x >= mod) x -= mod;return x;
}
int sub(int x, int y) {x -= y;if (x < 0) x += mod;return x;
}
int mul(int a, int b) {return a * b % mod;
}void work() {cin >> n >> x;for (int i = 1; i <= n; ++i) C[i][0] = 1, C[i][1] = i;for (int i = 1; i <= n; ++i) {for (int j = 2; j <= i; ++j) {C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;}}f[1][0] = f[0][0] = 1;for (int i = 2; i <= n; ++i) {for (int j = 1; j <= x; ++j) {if (j < i) f[i][j] = sub(quickpow(j, i), quickpow(j - 1, i));else {for (int k = 0; k <= i; ++k) {f[i][j] = add(f[i][j], mul(C[i][k], mul(quickpow(i - 1, k), f[i - k][j - i + 1])));}}}}int ans = 0;for (int i = 1; i <= x; ++i)ans = add(ans, f[n][i]);cout << ans << endl;
}