卷积太巨了!
Address
https://www.lydsy.com/JudgeOnline/problem.php?id=4555
Solution
分析后得出结论:题目中给出的第二类斯特林数递推公式是没用的。
首先要知道第二类斯特林数的通项公式:
证明: https://blog.csdn.net/xyz32768/article/details/80818366
然后,
当 时, 。因此可以把 换成 。
设 ,那么:
那么,原式
把只与 , 和 的式子分开:
设 , ,
那么容易看出这是一个卷积的形式:
NTT 直接码上。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define Pow(k, n) for (k = 1; k < n; k <<= 1)
#define Step(i, a, b, x) for (i = a; i <= b; i += x)
using namespace std;
const int N = 3e5 + 5, PYZ = 998244353;
int n, f[N], g[N], res[N], a[N], fac[N], in[N], inv[N], m = 1, cnt, ans,
rev[N], pw[N];
int qpow(int a, int b) {
int res = 1; while (b) b & 1 ? res = 1ll * res * a % PYZ : 0,
a = 1ll * a * a % PYZ, b >>= 1; return res;
}
void NTT(int *a, int g) {
int i, j, k, r = cnt; For (i, 0, m - 1) if (i < rev[i]) swap(a[i], a[rev[i]]);
pw[0] = g; For (i, 1, cnt - 1) pw[i] = 1ll * pw[i - 1] * pw[i - 1] % PYZ;
Pow (k, m) {
int x = pw[--r]; Step (i, 0, m - 1, k << 1) {
int w = 1; For (j, 0, k - 1) {
int u = a[i + j], v = 1ll * w * a[i + j + k] % PYZ;
a[i + j] = (u + v) % PYZ; a[i + j + k] = (u - v + PYZ) % PYZ;
w = 1ll * w * x % PYZ;
}
}
}
}
int main() {
int i, _g; cin >> n; fac[0] = 1;
For (i, 1, n) fac[i] = 1ll * fac[i - 1] * i % PYZ;
in[1] = 1; For (i, 2, n) in[i] = 1ll * (PYZ - PYZ / i) * in[PYZ % i] % PYZ;
inv[n] = qpow(fac[n], PYZ - 2); Rof (i, n - 1, 0)
inv[i] = 1ll * inv[i + 1] * (i + 1) % PYZ;
For (i, 0, n) f[i] = 1ll * ((i & 1) ? PYZ - 1 : 1) * inv[i] % PYZ;
g[g[0] = 1] = n + 1; For (i, 2, n) g[i] = 1ll * (qpow(i, n + 1) - 1)
* in[i - 1] % PYZ * inv[i] % PYZ;
a[0] = 1; For (i, 1, n) a[i] = 2ll * a[i - 1] % PYZ;
For (i, 1, n) a[i] = 1ll * a[i] * fac[i] % PYZ;
while (m <= (n << 1)) m <<= 1, cnt++; For (i, 0, m - 1)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << cnt - 1);
_g = qpow(3, 119 * qpow(2, 23 - cnt)); NTT(f, _g); NTT(g, _g);
For (i, 0, m - 1) res[i] = 1ll * f[i] * g[i] % PYZ;
NTT(res, qpow(_g, PYZ - 2)); For (i, 0, n)
ans = (ans + 1ll * a[i] *
(1ll * res[i] * qpow(m, PYZ - 2) % PYZ) % PYZ) % PYZ;
cout << ans << endl; return 0;
}