我最近怎么总是做生成函数的题目
题目大意
对于给定的 n , k , D n,k,D n,k,D, 求 ∑ [ ∑ a i = D ] D ! ∏ ( a i + k ) ! \sum_{[\sum a_i = D]}\frac{D!}{\prod(a_i+k)!} ∑[∑ai=D]∏(ai+k)!D!
若答案表示为 x y \frac{x}{y} yx 则输出 x y m o d 998244353 \frac{x}{y}\space mod\space 998244353 yx mod 998244353
其中
1
≤
n
≤
50
0
≤
k
≤
50
0
≤
D
≤
1
0
8
1 \leq n \leq 50 \\0\leq k\leq50 \\0\leq D \leq 10^8
1≤n≤500≤k≤500≤D≤108
我是链接
题目分析
前置芝士(结论)
∑ [ ∑ 1 n a i = D ] D ! ∏ 1 n a i ! = n D \sum_{[\sum_1^n a_i = D]} \frac{D!}{\prod_1^n a_i!} = n^D [∑1nai=D]∑∏1nai!D!=nD
这个结论理解为在 [ 1.. n ] [1..n] [1..n]中选数, 组成长度为 D D D的数列的方案数, a i a_i ai 表示 i i i在这个数列中出现的次数
D ! D! D!是全排列, 除掉的 ∏ a i ! \prod a_i! ∏ai!是对于每一个数的重复方案数, D ! ∏ 1 n a i \frac{D!}{\prod_1^n a_i} ∏1naiD!是对于一个特定数列 a i a_i ai的产生的方案数,求和便得到了所有组合的方案数。所有组合的方案数必定是每一位都是 n n n种可能性,所以求和得到了 n D n^D nD
因此可以得知
∑
[
∑
1
n
a
i
=
D
]
1
∏
1
n
a
i
!
=
n
D
D
!
\sum_{[\sum_1^n a_i = D]} \frac{1}{\prod_1^n a_i!} = \frac{n^D}{D!}
[∑1nai=D]∑∏1nai!1=D!nD
而这个问题使用生成函数解释为
构造指数型母函数 g k ( x ) = ∑ 0 ∞ x i i ! = e x g_k(x) = \sum_0^\infty \frac{x^i}{i!} = e^x gk(x)=∑0∞i!xi=ex表示对于第 k k k个数字选取了 i i i次
那么总共的方案数就有 f ( x ) = ∏ 1 n g k ( x ) f(x) = \prod_1^n g_k(x) f(x)=∏1ngk(x)其中第 D D D项的系数就表示从 [ 1.. n ] [1..n] [1..n]中生成序列的方案数,就是上文中的 n D D ! \frac{n^D}{D!} D!nD
所以 f ( x ) = ( e x ) n f(x) = (e^x)^n f(x)=(ex)n
f ( x ) f(x) f(x)的第 D D D项的系数为 n D D ! \frac{n^D}{D!} D!nD
正经分析
本题题目可以改写为
∑
[
∑
a
i
=
D
+
n
k
,
a
i
>
k
]
D
!
∏
(
a
i
)
!
=
D
!
∗
∑
[
∑
a
i
=
D
+
n
k
,
a
i
>
k
]
1
∏
(
a
i
)
!
\sum_{[\sum a_i = D+nk, \space a_i > k]}\frac{D!}{\prod(a_i)!} \\=D!\space *\sum_{[\sum a_i = D+nk, \space a_i > k]}\frac{1}{\prod(a_i)!}
[∑ai=D+nk, ai>k]∑∏(ai)!D!=D! ∗[∑ai=D+nk, ai>k]∑∏(ai)!1
发现将
D
!
D!
D!提出后剩下的部分由上文的解释方法为从
[
1..
n
]
[1..n]
[1..n]中选取数字,每个数字至少选取
k
k
k次,生成总长度为
D
+
n
k
D+nk
D+nk的序列,求总方案数
所以这部分使用生成函数来解释
g
k
(
x
)
=
∑
k
∞
x
i
i
!
=
e
x
−
∑
0
k
−
1
x
i
i
!
f
(
x
)
=
∏
1
n
g
k
(
x
)
=
(
e
x
−
∑
0
k
−
1
x
i
i
!
)
n
f
(
x
)
=
e
n
x
−
(
n
1
)
e
(
n
−
1
)
x
(
∑
0
k
−
1
x
i
i
!
)
+
.
.
.
=
∑
0
n
(
−
1
)
i
(
n
i
)
e
(
n
−
i
)
x
(
∑
0
k
−
1
x
j
j
!
)
i
g_k(x) = \sum_k^\infty \frac{x^i}{i!} = e^x - \sum_0^{k-1}\frac{x^i}{i!} \\f(x) = \prod_1^ng_k(x) = (e^x - \sum_0^{k-1}\frac{x^i}{i!})^n \\f(x) = e^{nx} - \binom{n}{1}e^{(n-1)x}(\sum_0^{k-1}\frac{x^i}{i!})+... \\=\sum_0^n(-1)^i\binom{n}{i}e^{(n-i)x}(\sum_0^{k-1}\frac{x^j}{j!})^i
gk(x)=k∑∞i!xi=ex−0∑k−1i!xif(x)=1∏ngk(x)=(ex−0∑k−1i!xi)nf(x)=enx−(1n)e(n−1)x(0∑k−1i!xi)+...=0∑n(−1)i(in)e(n−i)x(0∑k−1j!xj)i
剩下的部分就是
f
(
x
)
f(x)
f(x)在
x
D
+
n
k
x^{D+nk}
xD+nk处的系数
所以怎么才能求出这个系数 S S S呢
如果 ( ∑ 0 k − 1 x j j ! ) i (\sum_0^{k-1}\frac{x^j}{j!})^i (∑0k−1j!xj)i展开的各项系数为 K i , j K_{i,j} Ki,j, 而 e ( n − i ) x e^{(n-i)x} e(n−i)x在 j j j处的系数为 S i , j S_{i,j} Si,j
那么
S
=
∑
0
n
(
−
1
)
i
(
n
i
)
(
∑
0
i
(
k
−
1
)
S
i
,
D
+
n
k
−
j
K
i
,
j
)
S = \sum_0^n(-1)^i\binom{n}{i}(\sum_0^{i(k-1)} S_{i,D+nk-j}K_{i,j})
S=0∑n(−1)i(in)(0∑i(k−1)Si,D+nk−jKi,j)
我们发现
S
i
,
j
=
(
n
−
i
)
j
j
!
S_{i,j} = \frac{(n-i)^j}{j!}
Si,j=j!(n−i)j 也就是说
S
i
,
D
+
n
k
−
j
=
(
n
−
i
)
(
D
+
n
k
−
j
)
(
D
+
n
k
−
j
)
!
S_{i,D+nk-j} = \frac{(n-i)^{(D+nk-j)}}{(D+nk-j)!}
Si,D+nk−j=(D+nk−j)!(n−i)(D+nk−j)
而
K
i
,
j
K_{i,j}
Ki,j可以由递推的方式求出
(
K
i
−
1
,
0
+
K
i
−
1
,
1
x
+
.
.
.
+
K
i
−
1
,
i
(
k
−
1
)
x
i
(
k
−
1
)
)
(
∑
0
k
−
1
x
j
j
!
)
∴
K
i
,
j
=
∑
x
=
0
k
−
1
K
i
−
1
,
k
−
x
∗
1
x
!
,
j
∈
[
0
,
i
(
k
−
1
)
]
(K_{i-1,0}+K_{i-1,1}x+...+K_{i-1, i(k-1)}x^{i(k-1)})(\sum_0^{k-1}\frac{x^j}{j!}) \\\therefore K_{i,j}=\sum_{x=0}^{k-1}K_{i-1,k-x}*\frac{1}{x!}, j \in [0, i(k-1)]
(Ki−1,0+Ki−1,1x+...+Ki−1,i(k−1)xi(k−1))(0∑k−1j!xj)∴Ki,j=x=0∑k−1Ki−1,k−x∗x!1,j∈[0,i(k−1)]
有了递推式,就可以使用DP的方式求出
K
i
,
j
K_{i,j}
Ki,j了
可是这个题目并没有结束,1e8的范围求若干次阶乘,时间复杂度无法接受,因此将 D ! D! D!乘进去,与 S i , D + n k − j S_{i,D+nk-j} Si,D+nk−j结合, 得到 ( n − i ) ( D + n k − j ) D ! ( D + n k − j ) ! \frac{(n-i)^{(D+nk-j)}D!}{(D+nk-j)!} (D+nk−j)!(n−i)(D+nk−j)D!将 D ! ( D + n k − j ) ! \frac{D!}{(D+nk-j)!} (D+nk−j)!D!结合计算,发现每次最多只需要计算 n k nk nk个数相乘,时间变得非常充裕
综上
A
N
S
=
D
!
∗
S
=
∑
0
n
(
−
1
)
i
(
n
i
)
(
∑
0
i
(
k
−
1
)
(
n
−
i
)
D
+
n
k
−
j
D
!
(
D
+
n
k
−
j
)
!
K
i
,
j
)
ANS = D!*S = \sum_0^n(-1)^i\binom{n}{i}(\sum_0^{i(k-1)} (n-i)^{D+nk-j}\frac{D!}{(D+nk-j)!}K_{i,j})
ANS=D!∗S=0∑n(−1)i(in)(0∑i(k−1)(n−i)D+nk−j(D+nk−j)!D!Ki,j)
由此我们解决了求 S S S的若干问题,DP求 K K K的复杂度为 O ( ( n k ) 2 ) O((nk)^2) O((nk)2) 最后统计答案的时间复杂度为 O ( n 2 k ) O(n^2k) O(n2k)
所以最后的时间复杂度为 O ( ( n k ) 2 ) O((nk)^2) O((nk)2)
通过了这个题目
通过代码
人比较菜,代码比较丑,dalao勿喷
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 50;
const int MOD = 998244353;
typedef long long ll;
ll dp[MAXN + 10][MAXN * MAXN + 10];
ll qp(ll a, int b)
{
ll ans = 1;
while(b)
{
if(b & 1)
ans = (ans * a) % MOD;
b >>= 1;
a = (a * a) % MOD;
}
return ans;
}
ll inv(ll a)
{
return qp(a, MOD - 2);
}
ll fac[50 * 50 + 100];
ll facInv[50 * 50 + 100];
ll facDInv[50 * 50 + 100];
ll C(int n, int m)
{
return (((fac[n] * facInv[m]) % MOD) * facInv[n - m]) % MOD;
}
int main()
{
int n,k,d;
scanf("%d%d%d", &n, &k, &d);
fac[0] = 1;
for(int i = 1; i <= max(n * k, max(n, k)); ++i)
fac[i] = (fac[i - 1] * i) % MOD;
for(int i = 0; i <= max(n * k, max(n, k)); ++i)
facInv[i] = inv(fac[i]);
//dp 用来计算$$(e^x-\sum{i=0}{k-1}\frac{x^i}{i!})^n$$的各项系数中非e^?的部分
dp[0][0] = 1;
for(int i = 1; i <= n; ++i)
{
for(int j = 0; j <= i * (k - 1); ++j)
{
for(int x = 0; x <= min(j, k - 1); ++x)
{
dp[i][j] += (dp[i - 1][j - x] * facInv[x]) % MOD;
dp[i][j] %= MOD;
}
}
}
facDInv[0] = 1;
for(int i = 1; i <= n * k; ++i)
facDInv[i] = (facDInv[i - 1] * ((d + i) % MOD)) % MOD;
for(int i = 1; i <= n * k; ++i)
facDInv[i] = inv(facDInv[i]);
ll ans = 0;
int sgn = -1;
for(int i = 0; i <= n; ++i)
{
sgn *= -1;
ll tmp = 0;
for(int j = 0; j <= i * (k - 1); ++j)
{
tmp +=(((dp[i][j] * qp(n - i, d + n * k - j)) % MOD) * facDInv[n * k - j]) % MOD;
tmp %= MOD;
}
tmp *= C(n, i);
tmp %= MOD;
tmp *= sgn;
tmp %= MOD;
ans += tmp;
ans %= MOD;
}
ans += MOD;
ans %= MOD;
printf("%lld\n", ans);
return 0;
}