原题链接
https://ac.nowcoder.com/acm/contest/11255/G
题目大意
给定三个整数
n
,
k
,
D
(
1
≤
n
,
k
≤
50
,
0
≤
D
≤
1
0
8
)
n,k,D(1 \leq n,k \leq 50,0 \leq D \leq 10^8)
n,k,D(1≤n,k≤50,0≤D≤108)。
定义非负整数序列
a
a
a的权值为
D
!
∏
i
=
1
n
(
a
i
+
k
)
!
\frac{D!}{\prod\limits_{i=1}^{n}(a_i+k)!}
i=1∏n(ai+k)!D!
求所有满足以下条件的非负整数序列
a
a
a的权值和:
1.
∀
∈
[
1
,
n
]
,
a
i
≥
0
\forall\in[1,n],a_i \ge 0
∀∈[1,n],ai≥0
2.
∑
i
=
1
n
a
i
=
D
\sum_{i=1}^{n}a_i=D
∑i=1nai=D
答案对
998244353
998244353
998244353取模。
题解
我们可以把题目转化成把 D D D个小球分成 n n n组,每组 a i a_i ai个球。
①我们先不考虑
+
k
+k
+k的情况,将
D
D
D个不同的求分为
n
n
n组,每个球有
n
n
n种分组可能,总共方案数为
n
D
n^D
nD
∑
a
i
≥
0
,
∑
i
=
1
n
a
i
=
D
D
!
∏
i
=
1
n
a
i
!
\sum^{}_{a_i≥0,\sum\limits^{n}_{i=1}a_i=D}\frac{D!}{\prod\limits_{i=1}^{n}a_i!}
ai≥0,i=1∑nai=D∑i=1∏nai!D!
则
(
D
+
n
k
)
(D+nk)
(D+nk)个球分
n
n
n组的总方案书为
n
D
+
n
k
n^{D+nk}
nD+nk。
②将
+
k
+k
+k合并入
a
i
a_i
ai中:
∑
a
i
≥
k
,
∑
i
=
1
n
a
i
=
D
+
n
k
D
!
∏
i
=
1
n
a
i
!
\sum^{}_{ai≥k,\sum\limits^{n}_{i=1}a_i=D+nk}\frac{D!}{\prod^{n}_{i=1}a_i!}
ai≥k,i=1∑nai=D+nk∑∏i=1nai!D!
将②中
a
i
≥
k
a_i≥k
ai≥k换成
a
i
≥
0
a_i≥0
ai≥0,与①可推得总方案数(包括不合理方案):
D
!
(
D
+
n
k
)
!
n
D
+
n
k
\frac{D!}{(D+nk)!}n^{D+nk}
(D+nk)!D!nD+nk
设
d
p
i
,
j
dp_{i,j}
dpi,j表示
j
j
j个不同的求分为
i
i
i个非法组(即魅族的球数都小于
k
k
k),通过美剧最后一个非法组的球数与球的分配情况,得转移式:
d
p
i
,
j
=
∑
t
=
0
k
−
1
d
p
i
−
1
,
j
−
t
C
j
t
dp_{i,j}=\sum^{k-1}_{t=0}dp_{i-1,j-t}C_{j}^{t}
dpi,j=t=0∑k−1dpi−1,j−tCjt
通过计算,得出最终转移式:
D
!
(
D
+
n
k
)
!
∑
i
=
0
n
(
−
1
)
i
∑
j
=
0
i
(
k
−
1
)
d
p
i
,
j
×
C
n
i
×
C
D
+
n
k
j
×
d
p
i
,
j
(
n
−
i
)
D
+
n
k
−
j
\frac{D!}{(D+nk)}!\sum^{n}_{i=0}(-1)^i\sum^{i(k-1)}_{j=0}dp_{i,j}\times C^{i}_{n}\times C^{j}_{D+nk}\times dp_{i,j}(n-i)^{D+nk-j}
(D+nk)D!!i=0∑n(−1)ij=0∑i(k−1)dpi,j×Cni×CD+nkj×dpi,j(n−i)D+nk−j
参考代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=55;
const int MOD=998244353;
ll powmod(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)ret=ret*a%MOD;
a=a*a%MOD;
b>>=1;
}
return ret;
}
ll C[N*N][N*N],dp[N][N*N];
ll n,k,D;
void init()
{
for(int i=0;i<N*N;i++)
C[i][0]=1;
for(int i=1;i<N*N;i++)
for(int j=1;j<=min(N,i);j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
dp[0][0]=1;
for(int i=0;i<n;i++)
for(int j=0;j<=i*(k-1);j++)
for(int t=0;t<k;t++)
dp[i+1][j+t]=(dp[i+1][j+t]+dp[i][j]*C[j+t][t])%MOD;
}
int main()
{
scanf("%lld%lld%lld",&n,&k,&D);
init();
D+=n*k;
ll ans=0;
for(int i=0;i<=n;i++)
{
ll v=1;
for(int j=0;j<=i*(k-1);j++)
{
ll num=(i&1?MOD-C[n][i]:C[n][i]);
num=num*powmod(n-i,D-j)%MOD*dp[i][j]%MOD*v%MOD;
ans=(ans+num)%MOD;
v=v*(D-j)%MOD*powmod(j+1,MOD-2)%MOD;
}
}
for(int i=D-n*k+1;i<=D;i++)
ans=ans*powmod(i,MOD-2)%MOD;
cout<<ans;
}