【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=4555
【题解】
考虑第二类斯特林数的公式:
xn=∑xi=0(xi)i!∗Sn,i
x
n
=
∑
i
=
0
x
(
i
x
)
i
!
∗
S
n
,
i
就是先枚举选了几个格子,再乘以顺序。
对这个式子做二项式反演,得:
Sn,x=1x!∑xi=0(−1)x−i(xi)in
S
n
,
x
=
1
x
!
∑
i
=
0
x
(
−
1
)
x
−
i
(
i
x
)
i
n
用此方法来化简问题中的式子:
∑ni=0∑ij=0Si,j∗2j∗j!
∑
i
=
0
n
∑
j
=
0
i
S
i
,
j
∗
2
j
∗
j
!
=∑ni=0∑ij=02j∑jk=0(−1)j−k(jk)ki
=
∑
i
=
0
n
∑
j
=
0
i
2
j
∑
k
=
0
j
(
−
1
)
j
−
k
(
k
j
)
k
i
由于当
i<j
i
<
j
时
Si,j=0
S
i
,
j
=
0
所以
j
j
的枚举上界改为。
同时展开组合数:
=∑ni=0∑nj=02j∗j!∑jk=0(−1)j−k1k!(j−k)!∗ki
=
∑
i
=
0
n
∑
j
=
0
n
2
j
∗
j
!
∑
k
=
0
j
(
−
1
)
j
−
k
1
k
!
(
j
−
k
)
!
∗
k
i
改变求和顺序:
=∑nj=02j∗j!∑jk=0(−1)j−k(j−k)!∑ni=0kik!
=
∑
j
=
0
n
2
j
∗
j
!
∑
k
=
0
j
(
−
1
)
j
−
k
(
j
−
k
)
!
∑
i
=
0
n
k
i
k
!
=∑nj=02j∗j!∑k+t=j−1tt!∑ni=0kik!
=
∑
j
=
0
n
2
j
∗
j
!
∑
k
+
t
=
j
−
1
t
t
!
∑
i
=
0
n
k
i
k
!
那么后面的和式就变成了卷积的形式,NTT即可。
时间复杂度
O(N∗logN)
O
(
N
∗
l
o
g
N
)
【代码】
/* - - - - - - - - - - - - - - -
User : VanishD
problem : [bzoj4555]
Points : stirling
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define ll long long
# define N 300010
using namespace std;
const int inf = 0x3f3f3f3f, INF = 0x7fffffff;
const ll infll = 0x3f3f3f3f3f3f3f3fll, INFll = 0x7fffffffffffffffll;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
const int P = 998244353, G = 3;
int mul[N], n, a[N], b[N], ans, l;
int power(int x, int y){
int i = x; x = 1;
while (y > 0){
if (y % 2 == 1) x = 1ll * x * i % P;
i = 1ll * i * i % P;
y /= 2;
}
return x;
}
void NTT(int *a, int l, int tag){
for (int i = 0, j = 0; i < l; i++){
if (i < j) swap(a[i], a[j]);
for (int k = (l >> 1); (j ^= k) < k; k >>= 1);
}
for (int i = 1; i < l; i *= 2){
int wn = power(G, (P - 1) / (i * 2));
if (tag == -1) wn = power(wn, P - 2);
for (int j = 0; j < l; j += i * 2)
for (int k = 0, w = 1; k < i; k++, w = 1ll * w * wn % P){
int x = a[k + j], y = 1ll * w * a[k + i + j] % P;
a[k + j] = (x + y) % P; a[k + i + j] = (x - y) % P;
}
}
if (tag == -1){
int inv = power(l, P - 2);
for (int i = 0; i < l; i++) a[i] = 1ll * a[i] * inv % P;
}
}
int main(){
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
n = read();
mul[0] = 1;
for (int i = 1; i <= n; i++) mul[i] = 1ll * mul[i - 1] * i % P;
for (int i = 0; i <= n; i++){
a[i] = power(-1, i) * power(mul[i], P - 2);
if (i == 1) b[i] = n + 1;
else b[i] = 1ll * (power(i, n + 1) - 1) * power(i - 1, P - 2) % P * power(mul[i], P - 2) % P;
}
l = 1; while (l <= 2 * n) l <<= 1;
NTT(a, l, 1); NTT(b, l, 1);
for (int i = 0; i < l; i++) a[i] = 1ll * a[i] * b[i] % P;
NTT(a, l, -1);
for (int i = 0; i <= n; i++)
ans = (ans + 1ll * power(2, i) *mul[i] % P * a[i]) % P;
printf("%d\n", (ans + P) % P);
return 0;
}