CF 1606E. Arena
E. Arena
题意
有 \(n\) 个勇士一个角斗场决斗,初始时每个勇士最多有 \(x\) 滴血量,每一轮活着的勇士都会对其他勇士造成 \(1\) 滴伤害。
如果最后只剩下一个勇士活着,那么称他是获胜者。
问没有获胜者的方案数量。
分析
设 \(f(i, j)\) 表示有 \(i\) 个勇士,且每个勇士最多有 \(j\) 滴血量时,有获胜者的方案数量。
一轮过后,如果有 \(k\) 个勇士死亡,那么转移为 \(f(i-k, j-i+1)\) 情况下有获胜者的方案数量。死亡的方案为 \(C^i_k\) ,同时这些死亡的勇士血量为 \(1 \sim i-1\) ,所以有 \((i-1)^k\) 种方案。
所以状态转移方程为:
\[ f(i, j) = \sum^{i-1}_{k=0} f(i-k, j-i+1) \times C^i_k
\times (i-1)^k
\]
Code
/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
using namespace std;
const int N = 505;
int n, x;
int C[N][N], Pow[N][N], f[N][N];
// f(i, j) 表示有i个人,最多血量为j时存在winner的方案数量
void get_C (int n, int x)
{
for (int i = 0; i <= n; i ++ )
for (int j = 0; j <= x; j ++ )
if (!j) C[i][j] = 1; else C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod;
}
void get_Pow (int n, int x)
{
for (int i = 0; i <= n; i ++ )
for (int j = 0; j <= x; j ++ )
if (!j) Pow[i][j] = 1; else Pow[i][j] = (long long) Pow[i][j-1] * i % mod;
}
void solve ()
{
cin >> n >> x;
get_C(n, x); get_Pow(x, n);
for (int i = 1; i <= x; i ++ ) f[1][i] = i;
for (int i = 2; i <= n; i ++ ) // 枚举有多少个人
for (int j = i; j <= x; j ++ ) // 枚举最高血量,因为求有winner的方案,血量下限为i
for (int k = 0; k < i; k ++ ) // 枚举这一轮死了多少人
f[i][j] = (f[i][j] + (long long) f[i-k][j-i+1] * C[i][k] % mod * Pow[i-1][k] % mod) % mod;
cout << (Pow[x][n] - f[n][x] + mod) % mod << endl;
}
signed main ()
{
cout.tie(0)->sync_with_stdio(0);
solve();
return 0;
}