cf1606 E. Arena

题意:

有 n 个人,每个回合开始时,每个人对其他所有人造成1点伤害;回合结束时结算伤害,血量小于 1 的死亡。

每个人的初始血量 \(\in [1,x]\),现在你要为 n 个人指定初始血量,问方案数

输入只有两个数,\(2\le n \le 500,1\le x\le 500\)

思路:

没搞懂没搞懂。下面复读一下官方题解

\(f(i,j)\) 表示当前有 \(i\) 个人存活,这 \(i\) 个人每个人(至今已经)受到了 \(j\) 点伤害的方案数

初始 \(f(n,0)=1\),目标 \(ans=\sum f(0,1\sim x)\)

假设现在有 \(i\) 个人存活,进行一个回合后剩下 \(k\) 个人存活(\(k\in [0,i]\)),那么

\(k\) 个人(至今已经)受到的伤害为 \(d = \min \{x,j+i-1\}\)

这一回合中死掉了 \(i-k\) 个人,他们的初始血量 \(\in (j,d]\)

那我们现在就安排一下这回合死掉的人就行了(为啥为啥为啥),即

\(f(k,d) += f(i,j)\cdot C_{i}^{i-k} (d-j)^{i-k}\)

式子里的组合数和幂都可以n^2预处理

void sol() {
    cin >> n >> x;
    f[n][0] = 1;
    for(int i = n; i; i--)
        for(int j = 0; j <= x; j++)
            for(int k = 0, d = min(x, j+i-1ll); k <= i; k++)
                add(f[k][d], f[i][j] * C[i][k] % mod * mi[d-j][i-k] % mod);

    ll ans = 0;
    for(int i = 1; i <= x; i++) ans += f[0][i];
    cout << ans % mod;
}
posted @ 2022-05-17 23:21  Bellala  阅读(41)  评论(0)    收藏  举报