CF1606E
题目大意:给定(n,x(n,xle500)),代表有(n)个人,每个人初始的血量在(1-x)之间,每一轮每一个活着的人会对其他活着的人(除了自己)造成一点伤害,求有多少种初始局面使得最终所有人都会死掉,对998244353
首先这个数据范围和题目第一反应都是DP考虑一下DP, 状态记录的是必要的信息,每一轮的伤害是和当前人数直接挂钩的,所以需要记录当前剩余人数.也就是说每一次转移都会考虑当前要死几个人,那么为了方便死的人的血量的计算,所以当前已经收到的伤害也是要记录的
设(f_{i,j})表示还剩下(i)人,活着的人每人收到了(j)点伤害的方案数
每次枚举这一轮死掉的人数,那么死掉的人的血量就应该处于(j + 1)到(max(x,j+i-1))之间
转移方程式
[f_{k,max(j+i-1,x)}=f_{i,j} * C_i^k*(i-k)^{max(x,j+i-1)-j}
]
当然为了满足最后所有人都死亡的条件
最多转移到(i >= 2)
最后(f_{0,i})的和就是所求
#include<bits/stdc++.h>
#define LL long long
#define mk make_pair
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
const int N = 505;
const LL mod = 998244353;
LL fac[N],inv[N],f[N][N];
int n,k,h;
LL tt[N][N];
inline int read(){
int v = 0,c = 1;char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') c = -1;
ch = getchar();
}
while(isdigit(ch)){
v = v * 10 + ch - 48;
ch = getchar();
}
return v * c;
}
inline LL quick(LL x,LL y){
LL res = 1;
while(y){
if(y & 1) res = res * x % mod;
y >>= 1;
x = x * x % mod;
}
return res;
}
inline LL C(int x,int y){
return fac[x] * inv[y] % mod * inv[x - y] % mod;
}
int main(){
n = read(),h = read();
fac[0] = 1,inv[0] = 1;
for(int i = 1;i <= 500;++i) fac[i] = fac[i - 1] * i % mod;
inv[500] = quick(fac[500],mod - 2);
for(int i = 500 - 1;i >= 1;--i) inv[i] = inv[i + 1] * (i + 1) % mod;
for(int i = 1;i <= 500;++i){
for(int j = 0;j <= 500;++j) tt[i][j] = quick(i,j);
}
f[n][0] = 1;
// printf("%lld
",C(5,3));
for(int i = n;i >= 2;--i){
for(int j = 0;j <= h;++j){
for(int k = i;k >= 0;--k){
int t = min(h,j + i - 1);
f[k][t] = (f[k][t] + f[i][j] * C(i,k) % mod * tt[t - j][i - k]) % mod;
// printf("from:%d %d to:%d %d %lld
",i,j,k,t,f[k][t]);
}
}
}
LL ans = 0;
for(int i = 0;i <= h;++i) ans += f[0][i];
printf("%lld
",ans % mod);
return 0;
}