G-Product
Spy_Savior题解
Ultraman-Ace题解
组合意义+容斥原理
转化后题目关键要求有D+nkD+nkD+nk个小球放在nnn个盒子中,每个盒子至少有k个小球的方案数。
题目的等价式子为
∑∑i=1nai=D+nk[ai≥k]D!∏i=1nai!\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=1nai=D+nk[ai≥0](D+nk)!∏i=1nai!=nD+nk\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=1nai=D+nk[ai≥0]D!∏i=1nai!=D!(D+nk)!nD+nk\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
关键是有了限制,考虑容斥原理:
dpi,j\text{dp}_{i,j}dpi,j表示jjj个球分到iii个非法组的方案数,枚举最后一个非法组的球数和jjj个求的分配情况即可
dpi,j=∑t=0k−1dpi−1,j−t(jt)\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)
容斥原理,设时间AiA_iAi表示第iii个组不合法,那么
∣A1ˉ⋂A2ˉ⋂⋯⋂Anˉ∣=∑i=0n{(−1)n∑j,k∣Aj∣⋃⋯⋃∣Ak∣}|\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;
}