G-Product
Spy_Savior题解
Ultraman-Ace题解
组合意义+容斥原理
转化后题目关键要求有
D
+
n
k
D+nk
D+nk个小球放在
n
n
n个盒子中,每个盒子至少有k个小球的方案数。
题目的等价式子为
∑
∑
i
=
1
n
a
i
=
D
+
n
k
[
a
i
≥
k
]
D
!
∏
i
=
1
n
a
i
!
\sum_{\sum_{i=1}^na_i=D+nk[a_i\ge k]}\frac{D!}{\prod_{i=1}^na_i!}
∑i=1nai=D+nk[ai≥k]∑∏i=1nai!D!
如果没有至少有k个小球的限制,那么根据组合意义
∑
∑
i
=
1
n
a
i
=
D
+
n
k
[
a
i
≥
0
]
(
D
+
n
k
)
!
∏
i
=
1
n
a
i
!
=
n
D
+
n
k
\sum_{\sum_{i=1}^{n}a_i=D+nk[a_i\ge 0]}\frac{(D+nk)!}{\prod_{i=1}^{n}a_i!}=n^{D+nk}
∑i=1nai=D+nk[ai≥0]∑∏i=1nai!(D+nk)!=nD+nk
可得
∑
∑
i
=
1
n
a
i
=
D
+
n
k
[
a
i
≥
0
]
D
!
∏
i
=
1
n
a
i
!
=
D
!
(
D
+
n
k
)
!
n
D
+
n
k
\sum_{\sum_{i=1}^na_i=D+nk[a_i\ge 0]}\frac{D!}{\prod_{i=1}^na_i!}=\frac{D!}{(D+nk)!}n^{D+nk}
∑i=1nai=D+nk[ai≥0]∑∏i=1nai!D!=(D+nk)!D!nD+nk
关键是有了限制,考虑容斥原理:
dp i , j \text{dp}_{i,j} dpi,j表示 j j j个球分到 i i i个非法组的方案数,枚举最后一个非法组的球数和 j j j个求的分配情况即可
dp i , j = ∑ t = 0 k − 1 dp i − 1 , j − t ( j t ) \text{dp}_{i,j}=\sum_{t=0}^{k-1}\text{dp}_{i-1,j-t}\binom{j}{t} dpi,j=t=0∑k−1dpi−1,j−t(tj)
容斥原理,设时间
A
i
A_i
Ai表示第
i
i
i个组不合法,那么
∣
A
1
ˉ
⋂
A
2
ˉ
⋂
⋯
⋂
A
n
ˉ
∣
=
∑
i
=
0
n
{
(
−
1
)
n
∑
j
,
k
∣
A
j
∣
⋃
⋯
⋃
∣
A
k
∣
}
|\bar{A_1}\bigcap\bar{A_2}\bigcap\dots \bigcap\bar {A_n}|=\sum_{i=0}^{n}\{(-1)^n\sum_{j,k}|A_j| \bigcup\dots\bigcup|A_k|\}
∣A1ˉ⋂A2ˉ⋂⋯⋂Anˉ∣=i=0∑n{(−1)nj,k∑∣Aj∣⋃⋯⋃∣Ak∣}
而对于其他组就没有限制条件,可以带入上述公式可以直接求得。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{
T res=0;T fg=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}
while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
return res*fg;
}
const ll mod=998244353;
int n,k;
ll D,C[2505][2505],dp[55][2505];
ll qmi(ll a,ll b)
{
ll v=1;
while(b)
{
if(b&1) v=v*a%mod;
b>>=1;
a=a*a%mod;
}
return v;
}
void init()
{
for(int i=0;i<=2500;i++)
for(int j=0;j<=i;j++)
C[i][j]=(j?C[i-1][j]+C[i-1][j-1]: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)%mod;
}
int main()
{
n=rd(),k=rd(),D=rd<ll>();
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*qmi(n-i,D-j)%mod*dp[i][j]%mod*v%mod;
ans=(ans+num)%mod;
v=v*(D-j)%mod*qmi(j+1,mod-2)%mod;
}
}
for(int i=D-n*k+1;i<=D;i++) ans=ans*qmi(i,mod-2)%mod;
printf("%lld\n",ans);
return 0;
}