Educational Codeforces Round 116 (Rated for Div. 2) E. Arena(组合数,DP )
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational Codeforces Round 116 (Rated for Div. 2) E. Arena(组合数,DP )相关的知识,希望对你有一定的参考价值。
考虑第一批人在第 k k k轮死掉,那么这些死掉的人血量在 [ ( k − 1 ) ∗ ( n − 1 ) + 1 , k ∗ ( n − 1 ) ] [(k-1)*(n-1)+1,k*(n-1)] [(k−1)∗(n−1)+1,k∗(n−1)]范围内
定义 f [ i ] [ j ] f[i][j] f[i][j]表示已经死了 i i i个人,且剩下的 n − i n-i n−i个人可以是 [ j + 1 , x ] [j+1,x] [j+1,x]的任何血量
转移的时候枚举下一批过了 k k k轮死掉 q q q人,那么容易推得下一批人的血量范围是
[ j + ( k − 1 ) ∗ ( n − i − 1 ) + 1 , j + k ∗ ( n − i − 1 ) ] [j+(k-1)*(n-i-1)+1,j+k*(n-i-1)] [j+(k−1)∗(n−i−1)+1,j+k∗(n−i−1)]
而且,剩下的 n − ( i + q ) n-(i+q) n−(i+q)人血量大于 j + k ∗ ( n − i − 1 ) j+k*(n-i-1) j+k∗(n−i−1)
转移就非常简单了,枚举下一批人过了 k k k轮死 q q q个
我们先令 l = j + ( k − 1 ) ∗ ( n − i − 1 ) + 1 l=j+(k-1)*(n-i-1)+1 l=j+(k−1)∗(n−i−1)+1, r = j + k ∗ ( n − i − 1 ) \\ \\ \\ \\ r=j+k*(n-i-1) r=j+k∗(n−i−1)
f [ i + q ] [ r ] + = ( n − i q ) ∗ f [ i ] [ j ] ∗ ( r − l + 1 ) q f[i+q][r]\\ += \\binom{n-i}{q}*f[i][j]*(r-l+1)^q f[i+q][r] +=(qn−i)∗f[i][j]∗(r−l+1)q
意思是从剩余的 n − i n-i n−i个人选出 q q q个人来死,每个人血量都应该是区间内的值有 r − l + 1 r-l+1 r−l+1种取法
看上去复杂度是 O ( n 4 ) O(n^4) O(n4),实际上由于有效状态有限,循环不满,甚至比 O ( n 3 ) O(n^3) O(n3)还快
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 3e5+10;
const int mod = 998244353;
int n,x,f[509][509],fac[509],base[509][509],c[509][509];
void init()
{
fac[0] = 1;
for(int i=1;i<=500;i++) fac[i] = fac[i-1]*i%mod;
for(int j=1;j<=500;j++) base[0][j] = 1;
for(int j=1;j<=500;j++)
for(int i=1;i<=500;i++)
base[i][j] = base[i-1][j]*j%mod;
//i个人最大血量为j时的方案(不考虑任何顺序)
for(int i=0;i<=500;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;
}
}
int C(int n,int m) { return c[n][m]; }
signed main()
{
init();
cin >> n >> x;
f[0][0] = 1;
for(int i=0;i<=n;i++)
for(int j=0;j<=x;j++)
{
if( f[i][j]==0 ) continue;
for(int q=1;q<=n-i-1;q++)//本次死人数目
for(int k=1; ;k++)//过了k轮再死的
{
int l = j+(k-1)*(n-i-1)+1, r = j+k*(n-i-1);
if( r>=x ) break;
f[i+q][r] = ( f[i+q][r]+C(n-i,q)*f[i][j]%mod*base[q][r-l+1]%mod )%mod;
}
}
int ans = 1, res = 0;
for(int i=1;i<=n;i++) ans = ans*x%mod;
for(int i=0;i<=x;i++) res = ( res+f[n-1][i]*(x-i)%mod )%mod;
ans = ( ans-res )%mod;
cout << ( ans%mod+mod )%mod;
}
以上是关于Educational Codeforces Round 116 (Rated for Div. 2) E. Arena(组合数,DP )的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 7 A
Educational Codeforces Round 7
Educational Codeforces Round 90
Educational Codeforces Round 33