CF1606 E. Arena
题意:
有n个英雄,每一轮每个英雄向除自己之外的所有英雄发动一次攻击
每个英雄有初始血量,当承受攻击次数>=初始血量时,英雄死亡
如果最后存在一个英雄活到了最后,他就获胜
英雄初始血量上限为x
问有多少种英雄初始血量方案数,满足最后没有获胜的英雄
dp[i][j]表示现在还有i个英雄,活着的每个英雄已经承受j次攻击,在此情况下已经死亡英雄的初始血量方案数
设在这一轮攻击之后还剩下k个英雄活着
那么死亡了i-k个英雄
在这一轮死亡的英雄的血量至少为j+1,因为他活到了这一轮
至多为min(x,j+i-1),因为这一轮他承受了i-1次攻击,在这i-1次攻击里他死了,x时初始血量上限
所以如果一个英雄死在了这一轮,它的初始血量有min(x,j+i-1)- j 种可能
从i个英雄里选出i-k个死亡,有C(i,i-k)种选法
令nj=j+i-1
所以转移为dp[k][nj]+=dp[i][j]*C(i,i-k)*(nj-j)^(i-k)
#include<bits/stdc++.h> using namespace std; const int mod=998244353; #define N 505 int dp[N][N],C[N][N]; int main() { int n,x; scanf("%d%d",&n,&x); for(int i=0;i<=n;++i) C[i][0]=1; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; dp[n][0]=1; int nj,pw; for(int i=n;i>1;--i) for(int j=0;j<x;++j) { nj=min(j+i-1,x); pw=1; for(int k=i;k>=0;--k,pw=1ll*pw*(nj-j)%mod) dp[k][nj]=(dp[k][nj]+1ll*dp[i][j]*C[i][i-k]%mod*pw%mod)%mod; } int ans=0; for(int i=1;i<=x;++i) ans=(ans+dp[0][i])%mod; printf("%d",ans); }