Product | 2021牛客暑期多校训练营4 给你
n
,
k
,
D
n,k,D
n,k,D,你需要求出:
∑
D
=
∑
a
i
,
a
i
≥
0
D
!
∏
(
a
i
+
k
)
!
\sum_{D=\sum a_i,a_i\ge 0} \frac{D!}{\prod (a_i+k)!}
D=∑ai,ai≥0∑∏(ai+k)!D!
1
≤
n
≤
50
1\le n\le 50
1≤n≤50
0
≤
k
≤
50
0\le k\le 50
0≤k≤50
0
≤
D
≤
1
0
8
0\le D\le 10^8
0≤D≤108
思路
对现在的我来说也是神仙题,先学着点… 根据组合数学,我们有这个式子:
∑
D
=
∑
a
i
,
a
i
≥
0
D
!
∏
(
a
i
)
!
=
n
D
\sum_{D=\sum a_i,a_i\ge 0} \frac{D!}{\prod (a_i)!}=n^D
D=∑ai,ai≥0∑∏(ai)!D!=nD 为什么呢?左边的式子就相当于,有
D
D
D 个球,放进
n
n
n 个箱子里,球和箱子都不同的方案数,使用的是多重集的全排列公式 (因为一个集合里放进小球
A
B
AB
AB 与小球
B
A
BA
BA 当然是同一种方案,多了
a
i
!
a_i!
ai! 的方案数) 而等式右边就是,对于每一个球,放进这
n
n
n 个集合中的答案都不相同,所以就是
n
D
n^D
nD
进而,我们可以修改成和题意类似的式子:
∑
D
+
n
k
=
∑
a
i
,
a
i
≥
0
(
D
+
n
k
)
!
∏
(
a
i
)
!
=
n
D
+
n
k
\sum_{D+nk=\sum a_i,a_i\ge 0} \frac{(D+nk)!}{\prod (a_i)!}=n^{D+nk}
D+nk=∑ai,ai≥0∑∏(ai)!(D+nk)!=nD+nk 但是其实题意的式子是要我们求这样子:
A
n
s
=
∑
D
+
n
k
=
∑
a
i
,
a
i
≥
k
(
D
)
!
∏
(
a
i
)
!
Ans=\sum_{D+nk=\sum a_i,a_i\ge k} \frac{(D)!}{\prod (a_i)!}
Ans=D+nk=∑ai,ai≥k∑∏(ai)!(D)! 我们可以先稍微转换一下,变成这样:
A
n
s
=
D
!
(
D
+
n
k
)
!
∑
D
+
n
k
=
∑
a
i
,
a
i
≥
k
(
D
+
n
k
)
!
∏
(
a
i
)
!
(1)
Ans=\frac{D!}{(D+nk)!}\sum_{D+nk=\sum a_i,a_i\ge k} \frac{(D+nk)!}{\prod (a_i)!} \tag{1}
Ans=(D+nk)!D!D+nk=∑ai,ai≥k∑∏(ai)!(D+nk)!(1) 现在的问题就是,我们要求的是
a
i
≥
k
a_i\ge k
ai≥k ,但是我们的式子只支持我们
a
i
≥
0
a_i\ge 0
ai≥0 这个时候就要用到容斥了!(怎么又是你…)
我们定义合法的方法,就是这个集合中放了
≥
k
\ge k
≥k 个球;非法就是集合中放了
<
k
<k
<k 个球 设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示前
i
i
i 个集合,共放了
j
j
j 个球,且全部都是非法集合的方案数 这个转移是这样子的:
d
p
[
i
]
[
j
]
=
∑
t
=
0
k
−
1
d
p
[
i
−
1
]
[
j
−
t
]
×
C
j
t
dp[i][j]=\sum_{t=0}^{k-1}dp[i-1][j-t]\times C_j^t
dp[i][j]=t=0∑k−1dp[i−1][j−t]×Cjt 就是这
j
j
j 个球中,枚举时哪
t
t
t 个球放在第
i
i
i 个集合中
接下来算我们的答案,枚举
n
n
n 组中有
i
i
i 组不合法,这
i
i
i 组中用了
j
j
j 个球,方案就是
d
p
[
i
]
[
j
]
×
C
n
i
×
C
D
+
n
k
j
dp[i][j]\times C_n^i\times C_{D+nk}^j
dp[i][j]×Cni×CD+nkj 那么合法的组数就是
n
−
i
n-i
n−i 组,共用了
D
+
n
k
−
j
D+nk-j
D+nk−j 个球,根据我们之前的式子,方案数就是:
(
n
−
i
)
D
+
n
k
−
j
(n-i)^{D+nk-j}
(n−i)D+nk−j 再加上容斥的内容,还有我们 (1) 式中最左边的系数,就得到了:
A
n
s
=
D
!
(
D
+
n
k
)
!
×
∑
i
=
0
n
(
−
1
)
i
∑
j
=
0
(
i
−
1
)
k
(
d
p
[
i
]
[
j
]
×
C
n
i
×
C
D
+
n
k
j
)
×
(
(
n
−
i
)
D
+
n
k
−
j
)
Ans=\frac{D!}{(D+nk)!}\times \sum_{i=0}^n (-1)^i \sum_{j=0}^{(i-1)k} \Big(dp[i][j]\times C_n^i\times C_{D+nk}^j\Big) \times \Big( (n-i)^{D+nk-j} \Big)
Ans=(D+nk)!D!×i=0∑n(−1)ij=0∑(i−1)k(dp[i][j]×Cni×CD+nkj)×((n−i)D+nk−j)
代码
时间复杂度:
O
(
(
n
k
)
2
)
O((nk)^2)
O((nk)2) 主要是算
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 的时候的
#include<bits/stdc++.h>#defineIOSios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;typedeflonglong ll;voidshow(){std::cerr << endl;}template<typename T,typename... Args>voidshow(T x,Args... args){std::cerr <<"[ "<< x <<" ] , ";show(args...);}constint MAX =1e5+50;constint MOD =998244353;constint INF =0x3f3f3f3f;const ll LINF =0x3f3f3f3f3f3f3f3f;constdouble EPS =1e-5;
ll qpow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a%MOD;a=a*a%MOD;n>>=1;}return res;}
ll qpow(ll a,ll n,ll p){a%=p;ll res =1LL;while(n){if(n&1)res=res*a%p;a=a*a%p;n>>=1;}return res;}
ll npow(ll a,ll n){/* */ll res =1LL;while(n){if(n&1)res=res*a;a=a*a;n>>=1;if(res<0||a<0)return0;}return res;}
ll inv(ll a){/* */returnqpow(a,MOD-2);}
ll inv(ll a,ll p){returnqpow(a,p-2,p);}
ll dp[55][3500];
ll fac[3500],ivfac[3500];voidinit(int x){
fac[0]=1;for(int i =1;i <= x;++i)fac[i]= fac[i-1]* i % MOD;
ivfac[x]=inv(fac[x]);for(int i = x -1;~i;--i)ivfac[i]= ivfac[i+1]*(i+1)% MOD;}
ll C(int n,int m){if(n <0|| m > n)return0;return fac[n]* ivfac[m]% MOD * ivfac[n - m]% MOD;}intmain(){init(2500);
ll n,k,D;cin >> n >> k >> D;
dp[0][0]=1;for(int i =1;i <= n;++i){for(int j =0;j <=(k -1)* i;++j){for(int t =0;t <= k -1;++t){if(j-t>=0)dp[i][j]=(dp[i][j]+ dp[i-1][j-t]*C(j,t)% MOD)% MOD;}}}
ll ans =0;for(int i =0;i <= n;++i){
ll pm =(i&1)?-1:1;
ll tmp =1;for(int j =0;j <= i *(k -1);++j){
ans =(ans + pm * dp[i][j]*C(n,i)% MOD * tmp % MOD *qpow(n-i,D+n*k-j)% MOD + MOD)% MOD;
tmp = tmp *inv(j+1)% MOD *(D + n * k - j)% MOD;}}for(int i =1;i <= n * k;++i){
ans = ans *inv(D + i)% MOD;}
cout << ans;return0;}