返回顶部

Educational Codeforces Round 116 (Rated for Div. 2) E - Arena (dp计数)

代码+分析

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 998244353;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}

int n;
int x;
ll dp[505][505];

ll f[N],invf[N];
ll fpow(ll a,ll k){
	ll res=1;
	while(k){
		if(k&1) res=(res*a)%mod;
		k>>=1;
		a=a*a%mod;
		//cout<<1<<endl;
	}
	return res;
}
 
void init(int n){
	f[0]=1;
	for(int i=1;i<=n;++i){
		f[i]=f[i-1]*i%mod;
	}
	invf[n]=fpow(f[n],mod-2);
	for(int i=n-1;i>=0;--i){
		invf[i]=invf[i+1]*(i+1)%mod;
	}
}
 
 
ll C(int n,int k){
	if(k<0 || k>n) return 0;
	return f[n]*invf[k]%mod*invf[n-k]%mod;
}

//dp[i][j]表示有i个heros并且hp不大于j
//1.如果i-1>=j,一回合后all died,贡献为j^i
//2.如果i-1<j,那我们枚举一回合后还存活了k个人,
//  那么剩余的i-k个人每个人的生命值都是不大于(i-1)的,有(i-1)^{i-k}种方案
//  再看存活的k个人,首先有C(i,k)种选择方案,再看他们死的方案数dp[k][j-(i-1)]
//  最后得到:dp[i][j]+=c(i,k)*dp[k][j-(i+1)]*(i-1)^{i-k}

int main() {
    scanf("%d %d",&n,&x);
    init(1000000);    
    for(int i=2;i<=n;++i){
        for(int j=1;j<=x;++j){
            if(i-1>=j){
                dp[i][j]=fpow(j,i)%mod;
                continue;
            }
            for(int k=2;k<=i;++k){
                dp[i][j]=(dp[i][j]+C(i,k)*dp[k][j-(i-1)]%mod*fpow(i-1,i-k))%mod;
            }
            dp[i][j]=(dp[i][j]+fpow(i-1,i))%mod; //k=0的情况单独写一下
        }
    }
    printf("%lld\n",dp[n][x]);
    return 0;
}

posted @ 2021-11-01 19:02  Rayotaku  阅读(84)  评论(0编辑  收藏  举报