Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P5395 第二类斯特林数·行

P5395 第二类斯特林数·行

第二类斯特林数的一个性质:
$$
m ^ n = \sum _ {i = 1} ^ m {n \brace i} \binom m i i!
$$
相当于枚举每个集合的数量,从 $m$ 个集合中选出若干个,求斯特林数,集合可以任意排列。就等于 $n$ 个数任意放在 $m$ 个集合中。

二项式反演:
$$
f(n) = \sum _ {i = 0} ^ n \binom n i g(i) \Longleftrightarrow g(n) = \sum _ {i = 0} ^ n (-1) ^ {n - i} \binom n i f(i)
$$
可以得到,
$$
{n \brace m} = \sum _ {i = 1} ^ m \frac {(-1) ^ {m - i}} {(m - i) !} \frac {i ^ n} {i !}
$$
发现可以做卷积。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
template <class Type>
void read(Type &x)
{
char c;
bool flag = false;
while ((c = getchar()) < '0' || c > '9')
c == '-' && (flag = true);
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9')
x = (x << 3) + (x << 1) + c - '0';
flag && (x = ~x + 1);
}
template <class Type>
void write(Type x)
{
x < 0 && (putchar('-'), x = ~x + 1);
x > 9 && (write(x / 10), 0);
putchar(x % 10 + '0');
}
const int N = 1e6 + 10, mod = 167772161;
int rev[N];
int inv[N], fact[N], ifact[N];
int binpow(int b, int k)
{
int res = 1;
while (k)
{
if (k & 1)
res = (LL)res * b % mod;
b = (LL)b * b % mod;
k >>= 1;
}
return res;
}
void init(int n)
{
inv[1] = 1;
for (int i = 2; i <= n; i++)
inv[i] = -(LL)(mod / i) * inv[mod % i] % mod;
fact[0] = ifact[0] = 1;
for (int i = 1; i <= n; i++)
{
fact[i] = (LL)fact[i - 1] * i % mod;
ifact[i] = (LL)ifact[i - 1] * inv[i] % mod;
}
}
void PolyRev(int bit)
{
for (int i = 1; i < 1 << bit; i++)
rev[i] = rev[i >> 1] >> 1 | ((i & 1) << bit - 1);
}
void ntt(int *x, int bit, int op)
{
PolyRev(bit);
int tot = 1 << bit;
for (int i = 0; i < tot; i++)
rev[i] < i && (swap(x[rev[i]], x[i]), 0);
for (int mid = 1; mid < tot; mid <<= 1)
{
int w1 = binpow(3, (mod - 1) / (mid << 1));
op == -1 && (w1 = binpow(w1, mod - 2));
for (int i = 0; i < tot; i += mid << 1)
for (int j = 0, cur = 1; j < mid; j++, cur = (LL)cur * w1 % mod)
{
int p = x[i + j], q = (LL)cur * x[i + j + mid] % mod;
x[i + j] = (p + q) % mod, x[i + j + mid] = (p - q) % mod;
}
}
if (~op)
return;
int itot = binpow(tot, mod - 2);
for (int i = 0; i < tot; i++)
x[i] = (LL)x[i] * itot % mod;
}
int main()
{
int n;
read(n);
init(n);
static int A[N], B[N], len = n + 1;
for (int i = 0; i < len; i++)
A[i] = (LL)binpow(i, n) * ifact[i] % mod;
for (int i = 0; i < len; i++)
B[i] = ifact[i] * (i & 1 ? -1 : 1);
int bit = 0;
while (1 << bit < len << 1)
bit++;
ntt(A, bit, 1), ntt(B, bit, 1);
for (int i = 0; i < 1 << bit; i++)
A[i] = (LL)A[i] * B[i] % mod;
ntt(A, bit, -1);
for (int i = 0; i < len; i++)
write((A[i] + mod) % mod), putchar(' ');
return 0;
}