Educational Codeforces Round 116 (Rated for Div. 2) E. Arena

Educational Codeforces Round 116 (Rated for Div. 2) 的其他题解点我

E. Arena

题目链接


题目大意:

有n个人,每人有ai点生命值(ai <= k),每次每人会对其他所有人造成1点伤害。
生命值低于1的会死亡,给出 n 和 k ,问有多少种情况会出现场上无人存活
输出答案总数%998244353

2 , 1, 1 和 1 , 1 , 2 被视为两种

思路:

这题直接求好像有点困难, 我们采取间接法

也就是先求出剩下一个人的情况, 再用总数去减(最后肯定要么剩一个,要不全部死亡)
这里我们可以定义状态dp[n][k]n个人生命值在k内最后剩一个人的方案数

然后考虑状态转移

每次每个人会损失 i - 1 点生命值 ( i 为存活人数)
我们枚举每次死亡的人数 l,这些人的生命值小于i
以及所有可能的生命值j
d p [ i ] [ j ] + = d p [ i − l ] [ j − ( i − 1 ) ] ∗ ( i − 1 ) l ∗ C i l dp[i][j] += dp[i - l][j - (i - 1)] * (i - 1)^{l} * C_i^l dp[i][j]+=dp[il][j(i1)]i1lCil

死亡人数有 l 个,我们要从i个人中选出l个人来死亡,也就是 C i l C_i^l Cil
死亡的人中,因为收到的是 i - 1点伤害,所以他们每个人只要少于这个值都可以,总共是有l个人,也就是 ( i − 1 ) l (i - 1) ^ l (i1)l

这样解释应该能懂了吧

最后考虑最初状态

也就是只有一个人的时候

d p [ 1 ] [ j ] = j dp[1][j] = j dp[1][j]=j

AC代码:

#include <bits/stdc++.h>
#define PII pair<int,int>
#define ll long long

using namespace std;

const double eps = 1e-8;
const int maxn = 1e5 + 10;
const int mod = 998244353;
const int INF = 1<<30;
inline void swap(int &x, int &y){x^=y^=x^=y;}
inline int gcd(int a,int b) {return !b ? a : gcd(b,a%b);}

ll quick_pow(ll a, ll b){
    ll ans = 1;
    a %= mod;
    while(b){
        if(b & 1)ans *= a, ans %= mod;
        a *= a;a %= mod;
        b >>= 1;
    }
    return ans;
}
ll C[504][504];
void pre_C(int N){//递推预处理出组合数
    C[0][0] = 1; 
    for(int i = 1; i <= N; ++i){
        C[i][0] = 1;
        for(int j = 1; j <= i; ++j){
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
        }
    }
}
ll dp[504][504];
int main(){	
    pre_C(501);
    ll n, k;
    scanf("%lld %lld", &n, &k);
    for(int i = 1; i <= k; ++i)dp[1][i] = i;
    for(int i = 2; i <= n; ++i){
        for(int j = i; j <= k; ++j){
            for(int l = 0; l < i; ++l){
                dp[i][j] += 
                (dp[i - l][j - i + 1] * quick_pow(i - 1, l) % mod) * C[i][l]%mod;
                dp[i][j] %= mod;
            }
        }
    }
    printf("%lld\n", (quick_pow(k, n) - dp[n][k] + mod) % mod);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值