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;
}
posted @ 2021-11-20 13:32  Rainea  阅读(42)  评论(0)    收藏  举报