有關斯特林數的介紹和斯特林反演:斯特林數及斯特林反演。html
原本是想作容斥的,結果發現了一個多項式題目……ios
不過容斥和反演息息相關嘛。函數
這題作完以後感受卷積也不是那麼難,就把它理解成一個預處理一個複雜函數的方法就行了。這樣複雜度能夠從 \(O(n)\) 求和式變成 \(O(1)\) 取得函數值了。spa
這道題目是有關第二類斯特林數的,上文的博客中推導了第二類斯特林數的一個公式:code
\(\begin{aligned} \displaystyle S(n, m) = \frac{1}{m!} \sum_{k = 0}^m (-1)^k C(m, k) (m - k)^n \\ \displaystyle = \sum_{k = 0}^m \frac{(-1)^k (m - k)^n}{k!(m - k)!} \end{aligned}\)orm
發現上式是個卷積形式,因而本題的柿子能夠這樣推導(後兩步好神仙啊):htm
\(\begin{aligned} \displaystyle F(n) =\sum_{i=0}^n \sum_{j=0}^i S(i, j) * 2^j * j! \\ \displaystyle =\sum_{i=0}^n \sum_{j=0}^n S(i, j) * 2^j*j! \\ \displaystyle =\sum_{j=0}^n 2^j*j!\sum_{i=0}^n S(i, j) \\ \displaystyle =\sum_{j=0}^n 2^j*j!\sum_{i=0}^n \sum_{k=0}^j\frac{(-1)^k}{k!}\cdot\frac{(j-k)^i}{(j-k)!} \\ \displaystyle =\sum_{j=0}^n 2^j*j!\sum_{k=0}^j\frac{(-1)^k}{k!}\cdot\frac{ \sum_{i=0}^n (j-k)^i}{(j-k)!} \\ \displaystyle =\sum_{j=0}^n 2^j*j!\sum_{k=0}^j\frac{(-1)^k}{k!}\cdot \frac{(j-k)^{n+1}-1}{(j-k-1)(j-k)!} \\ \end{aligned}\)blog
這樣,這道題目的柿子也化成了卷積形式:get
\(\begin{aligned} \displaystyle f(x) = \frac{(-1)^x}{x!} \\ \displaystyle g(x) = \frac{x^{n+1}-1}{(x-1)*x!} \\ \displaystyle F(n) = \sum_{i = 0}^{n} 2^i * i! *(f×g)(i) \end{aligned}\)博客
能夠用 \(NTT\) 求解 …… 抄抄抄。
#include <cmath> #include <queue> #include <cstdio> #include <cctype> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int mod = 998244353; const int maxn = 400000 + 10; int n, len, rado, limit, r[maxn], fac[maxn], inv[maxn], f[maxn], g[maxn], pow_2[maxn], ans; inline int Fast_pow(int x, int p) { register int res = 1; for( ; p; x = 1ll * x * x % mod, p = p >> 1) if( p & 1 ) res = 1ll * x * res % mod; return res; } inline void Fast_numbertheory_transform(int *a, int type) { for(int i = 0; i < limit; ++i) if( i < r[i] ) swap(a[i], a[r[i]]); for(int mid = 1; mid < limit; mid = mid << 1) { int Base_p = Fast_pow(3ll, (mod - 1) / (mid << 1)); if( type == -1 ) Base_p = Fast_pow(Base_p, mod - 2); for(int l = 0, length = mid << 1; l < limit; l = l + length) { for(int k = 0, p = 1; k < mid; ++k, p = 1ll * p * Base_p % mod) { int x = a[l + k], y = 1ll * p * a[l + mid + k] % mod; a[l + k] = (x + y) % mod, a[l + mid + k] = (x - y + mod) % mod; } } } int inver = Fast_pow(limit, mod - 2); if( type == -1 ) for(int i = 0; i < limit; ++i) a[i] = 1ll * a[i] * inver % mod; } int main(int argc, char const *argv[]) { scanf("%d", &n), pow_2[0] = fac[0] = fac[1] = 1; for(int i = 1; i <= n; ++i) pow_2[i] = (pow_2[i - 1] << 1) % mod; for(int i = 2; i <= n; ++i) fac[i] = 1ll * i * fac[i - 1] % mod; inv[n] = Fast_pow(fac[n], mod - 2); for(int i = n; i >= 1; --i) inv[i - 1] = 1ll * inv[i] * i % mod; g[0] = 1, g[1] = n + 1; for(int i = 0; i <= n; ++i) f[i] = 1ll * ((i & 1) ? mod - 1 : 1) * inv[i] % mod; for(int i = 2; i <= n; ++i) g[i] = 1ll * (Fast_pow(i, n + 1) - 1 + mod) * Fast_pow(i - 1 + mod, mod - 2) % mod * inv[i] % mod; len = n << 1, rado = 0, limit = 1; while( limit < len ) limit = (limit << 1), ++rado; for(int i = 0; i < limit; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (rado - 1)); Fast_numbertheory_transform(f, 1); Fast_numbertheory_transform(g, 1); for(int i = 0; i < limit; ++i) f[i] = 1ll * f[i] * g[i] % mod; Fast_numbertheory_transform(f, -1); for(int i = 0; i <= n; ++i) ans = (ans + 1ll * fac[i] * pow_2[i] % mod * f[i] % mod) % mod; printf("%d\n", ans); return 0; }