【题目链接】
【前置技能】
- NTT
- 斯特林数
【题解】
-
∑
i
=
0
n
∑
j
=
0
i
S
(
i
,
j
)
∗
2
j
∗
j
!
\displaystyle \sum _{i=0}^{n} \sum _{j=0}^{i} S(i, j)*2^j*j!
i=0∑nj=0∑iS(i,j)∗2j∗j!
= ( ∑ i = 1 n ∑ j = 1 n S ( i , j ) ∗ 2 j ∗ j ! ) + 1 = \displaystyle (\sum _{i=1}^{n} \sum _{j=1}^{n} S(i, j)*2^j*j!) + 1 =(i=1∑nj=1∑nS(i,j)∗2j∗j!)+1【 S ( i , j ) S(i, j) S(i,j)在 i < j i < j i<j时的值为0,所以将 j j j的范围更改并不影响答案。 S ( i , j ) S(i, j) S(i,j)在 i = 0 i =0 i=0或 j = 0 j =0 j=0时,仅在 i = j = 0 i=j=0 i=j=0时的值不为 0 0 0,求和从 1 1 1开始就避免了展开后出现 0 0 0^0 00】
= ( ∑ j = 1 n 2 j ∗ j ! ∑ i = 1 n S ( i , j ) ) + 1 = (\displaystyle \sum _{j=1}^{n} 2^j*j!\sum _{i=1}^{n} S(i, j)) + 1 =(j=1∑n2j∗j!i=1∑nS(i,j))+1 【交换求和顺序】
= ( ∑ j = 1 n 2 j ∗ j ! ∑ i = 1 n 1 j ! ∑ t = 0 j ( − 1 ) t ∗ C j t ∗ ( j − t ) i ) + 1 = (\displaystyle \sum _{j=1}^{n} 2^j*j!\sum _{i=1}^{n} \frac {1} {j!} \sum _{t = 0}^{j} (-1)^t * C_j^t * (j - t)^i ) + 1 =(j=1∑n2j∗j!i=1∑nj!1t=0∑j(−1)t∗Cjt∗(j−t)i)+1 【展开 S ( i , j ) S(i, j) S(i,j)】
= ( ∑ j = 1 n 2 j ∗ j ! ∑ i = 1 n ∑ t = 0 j ( − 1 ) t ∗ 1 t ! ∗ ( j − t ) ! ∗ ( j − t ) i ) + 1 = (\displaystyle \sum _{j=1}^{n} 2^j*j!\sum _{i=1}^{n} \sum _{t = 0}^{j} (-1)^t * \frac{1}{t!*(j -t)!} * (j - t)^i ) + 1 =(j=1∑n2j∗j!i=1∑nt=0∑j(−1)t∗t!∗(j−t)!1∗(j−t)i)+1 【展开 C j t C_j^t Cjt并化简】
= ( ∑ j = 1 n 2 j ∗ j ! ∑ t = 0 j ( − 1 ) t t ! ∗ ∑ i = 1 n ( j − t ) i ( j − t ) ! ) + 1 = (\displaystyle \sum _{j=1}^{n} 2^j*j! \sum _{t = 0}^{j} \frac{(-1)^t}{t!} * \frac {\sum _{i=1}^{n}(j - t)^i}{(j -t)!} ) + 1 =(j=1∑n2j∗j!t=0∑jt!(−1)t∗(j−t)!∑i=1n(j−t)i)+1 【卷积满足结合律,交换求和顺序】 - 发现出现了卷积的形式,令 A i = ( − 1 ) i i ! A_i=\frac{(-1)^i}{i!} Ai=i!(−1)i, B i = ∑ j = 1 n i j i ! B_i = \frac {\sum _{j=1}^{n}i^j}{i!} Bi=i!∑j=1nij,则 A N S = ( ∑ i = 1 n 2 i ∗ i ! ∗ [ x i ] ( A ∗ B ) ) + 1 ANS = (\displaystyle \sum _{i=1}^{n} 2^i*i! *[x^i](A*B)) + 1 ANS=(i=1∑n2i∗i!∗[xi](A∗B))+1
- 时间复杂度 O ( N l o g N ) O(NlogN) O(NlogN)
【代码】
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define P 998244353
#define G 3
#define MAXN 262145
using namespace std;
int n, fac[MAXN], inv[MAXN], ans, Pow[MAXN];
int N, LOG, rev[MAXN], A[MAXN], B[MAXN];
template <typename T> void chkmin(T &x, T y){x = min(x, y);}
template <typename T> void chkmax(T &x, T y){x = max(x, y);}
template <typename T> void read(T &x){
x = 0; int f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
void update(int &x, int y){x += y; if (x >= P) x -= P;}
int inc(int x, int y){return (x + y >= P) ? (x + y - P) : (x + y);}
int dec(int x, int y){return (x - y < 0) ? (x - y + P) : (x - y);}
int mul(int x, int y){return 1ll * x * y % P;}
int qpow(int a, int b){
int ret = 1;
while (b) {
if (b & 1) ret = mul(ret, a);
a = mul(a, a);
b >>= 1;
}
return ret;
}
void init(int n){
N = 1, LOG = 0;
while (N <= n * 2) N <<= 1, ++LOG;
for (int i = 0; i < N; ++i)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (LOG - 1));
}
void ntt(int *a, int opt){
for (int i = 0; i < N; ++i)
if (rev[i] < i) swap(a[i], a[rev[i]]);
for (int len = 2; len <= N; len <<= 1){
int delta;
if (opt == 1) delta = qpow(G, (P - 1) / len);
else delta = qpow(G, P - 1 - (P - 1) / len);
for (int i = 0; i < N; i += len){
int cur = 1;
for (int j = i, t = i + len / 2; t < i + len; ++j, ++t){
int tmp = a[j], tnp = mul(cur, a[t]);
a[j] = inc(tmp, tnp), a[t] = dec(tmp, tnp);
cur = mul(cur, delta);
}
}
}
if (opt == -1) {
int INV = qpow(N, P - 2);
for (int i = 0; i < N; ++i)
a[i] = mul(a[i], INV);
}
}
void init(){
fac[0] = inv[0] = 1;
for (int i = 1; i <= n; ++i)
fac[i] = mul(fac[i - 1], i);
inv[n] = qpow(fac[n], P - 2);
for (int i = n - 1; i >= 1; --i)
inv[i] = mul(inv[i + 1], i + 1);
Pow[0] = 1;
for (int i = 1; i <= n; ++i)
Pow[i] = mul(Pow[i - 1], 2);
}
int main(){
read(n);
init(n);
init();
for (int i = 0; i <= n; ++i){
if (i & 1) A[i] = P - inv[i];
else A[i] = inv[i];
B[i] = inv[i];
if (!i) {B[i] = 0; continue;}
if (i == 1) {B[i] = n; continue;}
B[i] = mul(B[i], mul(inv[i - 1], fac[i - 2]));
B[i] = mul(B[i], dec(qpow(i, n + 1), i));
}
ntt(A, 1), ntt(B, 1);
for (int i = 0; i < N; ++i)
A[i] = mul(A[i], B[i]);
ntt(A, -1);
for (int i = 0; i <= n; ++i){
int tmp = mul(Pow[i], fac[i]);
tmp = mul(tmp, A[i]);
update(ans, tmp);
}
update(ans, 1);
printf("%d\n", ans);
return 0;
}