CF1606E

CF1606E

题目大意:给定\(n,x(n,x\le500)\),代表有\(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\n",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\n",i,j,k,t,f[k][t]);	
			}
		}
	}
	LL ans = 0;
	for(int i = 0;i <= h;++i) ans += f[0][i];
	printf("%lld\n",ans % mod);
    return 0;
}
 
posted @ 2021-11-05 16:42  wyxdrqcccc  阅读(40)  评论(0编辑  收藏  举报