CF1606E Arena 题解(动态规划)

考虑设 \(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;
}
posted @ 2025-10-20 21:44  小蛐蛐awa  阅读(6)  评论(0)    收藏  举报