题目链接
题目大意
求
f
(
n
)
=
∑
i
=
0
n
∑
j
=
0
n
S
(
i
,
j
)
2
j
(
j
!
)
f(n)=\sum_{i=0}^n\sum_{j=0}^nS(i,j)2^j(j!)
f(n)=i=0∑nj=0∑nS(i,j)2j(j!)
推式子
f ( n ) = ∑ i = 0 n ∑ j = 0 i S ( i , j ) 2 j ( j ! ) = ∑ i = 0 n ∑ j = 0 n S ( i , j ) 2 j ( j ! ) = ∑ j = 0 n 2 j ( j ! ) ∑ i = 0 n S ( i , j ) = ∑ j = 0 n 2 j ( j ! ) ∑ i = 0 n ∑ k = 0 j ( − 1 ) k 1 k ! ( j − k ) ! ( j − k ) i = ∑ j = 0 n 2 j ( j ! ) ∑ k = 0 j ( − 1 ) k 1 k ! ( j − k ) ! ∑ i = 0 n ( j − k ) i = ∑ j = 0 n 2 j ( j ! ) ∑ k = 0 j ( − 1 ) k k ! ∑ i = 0 n ( j − k ) i ( j − k ) ! \begin{aligned}f(n)&=\sum_{i=0}^{n}\sum_{j=0}^iS(i,j)2^j(j!)\\&=\sum_{i=0}^{n}\sum_{j=0}^nS(i,j)2^j(j!)\\&=\sum_{j=0}^{n}2^j(j!)\sum_{i=0}^nS(i,j)\\&=\sum_{j=0}^{n}2^j(j!)\sum_{i=0}^n\sum_{k=0}^j(-1)^k\frac{1}{k!(j-k)!}(j-k)^i\\&=\sum_{j=0}^{n}2^j(j!)\sum_{k=0}^j(-1)^k\frac{1}{k!(j-k)!}\sum_{i=0}^n(j-k)^i\\&=\sum_{j=0}^{n}2^j(j!)\sum_{k=0}^j\frac{(-1)^k}{k!}\frac{\sum_{i=0}^n(j-k)^i}{(j-k)!}\end{aligned} f(n)=i=0∑nj=0∑iS(i,j)2j(j!)=i=0∑nj=0∑nS(i,j)2j(j!)=j=0∑n2j(j!)i=0∑nS(i,j)=j=0∑n2j(j!)i=0∑nk=0∑j(−1)kk!(j−k)!1(j−k)i=j=0∑n2j(j!)k=0∑j(−1)kk!(j−k)!1i=0∑n(j−k)i=j=0∑n2j(j!)k=0∑jk!(−1)k(j−k)!∑i=0n(j−k)i
令 g ( n ) = ∑ k = 0 j ( − 1 ) k k ! ∑ i = 0 n ( j − k ) i ( j − k ) ! g(n)=\sum_{k=0}^{j}\frac{(-1)^k}{k!}\frac{\sum_{i=0}^n(j-k)^i}{(j-k)!} g(n)=∑k=0jk!(−1)k(j−k)!∑i=0n(j−k)i,发现这个式子可以卷积。
令 a i = ( − 1 ) i i ! , b i = ∑ k = 0 n i k i ! = i n + 1 − 1 ( i − 1 ) i ! a_i=\frac{(-1)^i}{i!},b_i=\frac{\sum_{k=0}^ni^k}{i!}=\frac{i^{n+1}-1}{(i-1)i!} ai=i!(−1)i,bi=i!∑k=0nik=(i−1)i!in+1−1,那么 g ( n ) = ∑ i = 0 n a i b n − i g(n)=\sum_{i=0}^na_ib_{n-i} g(n)=∑i=0naibn−i。所以 f ( n ) = ∑ i = 0 n 2 i ( i ! ) g ( i ) 。 f(n)=\sum_{i=0}^n2^i(i!)g(i)。 f(n)=∑i=0n2i(i!)g(i)。
时间复杂度 O(nlogn) \text{O(nlogn)} O(nlogn)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 5, mod = 998244353, G = 3, Gi = 332748118;
int n, lim = 1, L, r[N]; ll ans, fac[N], inv[N], a[N], b[N], g[N];
inline ll qpow(ll a, ll b) { ll ans = 1; for (; b ; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod; return ans; }
inline void get(int n = N - 1) {
fac[0] = 1; for (int i = 1; i <= n; ++ i) fac[i] = fac[i - 1] * i % mod;
inv[n] = qpow(fac[n], mod - 2); for (int i = n - 1; i >= 0; -- i) inv[i] = (i + 1) * inv[i + 1] % mod;
}
inline void NTT(ll *A, int type) {
for (int i = 0; i < lim; ++ i) if (i < r[i]) swap(A[i], A[r[i]]);
for (int mid = 1; mid < lim; mid <<= 1) {
ll Wn = qpow(type == 1 ? G : Gi, (mod - 1) / (mid << 1));
for (int j = 0; j < lim; j += (mid << 1)) {
ll w = 1;
for (int k = 0; k < mid; ++ k, w = w * Wn % mod) {
int x = A[j + k], y = w * A[j + k + mid] % mod;
A[j + k] = (x + y) % mod, A[j + k + mid] = (x - y + mod) % mod;
}
}
}
}
int main() {
scanf("%d", &n), get(n);
for (int i = 0; i <= n; ++ i) a[i] = qpow(mod - 1, i) * qpow(fac[i], mod - 2) % mod;
b[0] = 1, b[1] = n + 1; for (int i = 2; i <= n; ++ i) b[i] = (qpow(i, n + 1) - 1 + mod) % mod * qpow(i - 1, mod - 2) % mod * qpow(fac[i], mod - 2) % mod;
while (lim <= n + n) lim <<= 1, ++ L;
for (int i = 0; i < lim; ++ i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
NTT(a, 1), NTT(b, 1);
for (int i = 0; i < lim; ++ i) a[i] = a[i] * b[i] % mod;
NTT(a, -1);
ll inv = qpow(lim, mod - 2), x = 1;
for (int i = 0; i <= n; ++ i) g[i] = a[i] * inv % mod;
for (int i = 0; i <= n; ++ i, x = (x << 1) % mod) (ans += x * fac[i] % mod * g[i] % mod) %= mod;
return printf("%lld\n", ans), 0;
}