bzoj 4555 求和 - 线性筛 - 生成函数
$$
\begin {align}
f(n) &= \sum_{i = 0}^{n}\sum_{j = 0}^{i}\genfrac\{\}0{}{i}{j}j! 2^j \\
&= \sum_{i = 0}^{n}\sum_{j = 0}^{n}\genfrac\{\}0{}{i}{j}j! 2^j \\
&= \sum_{i = 0}^{n}\sum_{j = 0}^{n}\sum_{k = 0}^{j} k^i\binom{j}{k}(-1)^{j - k} 2^j \\
&= \sum_{j = 0}^{n}\sum_{k = 0}^{j} \binom{j}{k}(-1)^{j - k} 2^j \sum_{i = 0}^{n}k^i
\end {align}
$$
设$S_k(n) = \sum_{i = 0}^{n} k^i =\begin{cases}\frac{k^{n + 1} - 1}{k - 1}& (k\neq 1) \\ n + 1 &(k = 1)\end{cases} $
那么有$f(n) = \sum_{i = 0}^{n} \sum_{j = 0}^{i} \binom{i}{j}(-1)^{i - j} 2^i S_j(n + 1)$
注意到若$G(x) = \sum_{i = 0}^{n} g_i x^i$,那么$G(x + d) = \sum_{i = 0}^{n} \sum_{j = i}^{n} g_j \binom{j}{i} d^{j - i} x^i$
$$
\begin{align}
f(n) &= \sum_{j = 0}^{n} S_j(n) \sum_{i = j}^{n} \binom{i}{j} (-1)^{i - j} 2^{i}
\end{align}
$$
那么这里的$G(x) = \sum_{i = 0}^{n} 2^i x^i, d = -1$
$$
\begin{align}
G(x) &= \frac{(2x)^{n + 1} - 1}{2x - 1} \\
G(x - 1) &= \frac{2^{n + 1} (x - 1)^{n + 1} - 1}{2x - 3}
\end{align}
$$
用二项式定理展开上面的,剩下暴力多项式除。
逆元和$k^n$都可以线性预处理。然后就做完了。
Code
/** * bzoj * Problem#4555 * Accepted * Time: 156ms * Memory: 3256k */ #include <bits/stdc++.h> using namespace std; typedef bool boolean; #define ll long long const int Mod = 998244353; template <const int Mod = :: Mod> class Z { public: int v; Z() : v(0) { } Z(int x) : v(x){ } Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) { int x; return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x)); } friend Z operator - (const Z& a, const Z& b) { int x; return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x)); } friend Z operator * (const Z& a, const Z& b) { return Z(a.v * 1ll * b.v); } friend Z operator ~(const Z& a) { return inv(a.v, Mod); } friend Z operator - (const Z& a) { return Z(0) - a; } Z& operator += (Z b) { return *this = *this + b; } Z& operator -= (Z b) { return *this = *this - b; } Z& operator *= (Z b) { return *this = *this * b; } friend boolean operator == (const Z& a, const Z& b) { return a.v == b.v; } }; Z<> qpow(Z<> a, int p) { Z<> rt = Z<>(1), pa = a; for ( ; p; p >>= 1, pa = pa * pa) { if (p & 1) { rt = rt * pa; } } return rt; } typedef Z<> Zi; const int N = 1e5 + 5; int n; Zi Inv[N], _g[N], g[N]; void get_g() { Inv[0] = 0, Inv[1] = 1; for (int i = 2; i <= n + 1; i++) { Inv[i] = -Inv[Mod % i] * (Mod / i); } Zi C = 1, v = qpow(2, n + 1); for (int i = 0; i <= n + 1; i++) { _g[i] = v * C; if ((n + 1 - i) & 1) { _g[i] = -_g[i]; } C = C * (n - i + 1) * Inv[i + 1]; } _g[0] -= 1; // g = _g / (2x - 3) for (int i = n + 1; i; i--) { g[i - 1] = _g[i] * Inv[2]; _g[i - 1] += g[i - 1] * 3; } } Zi pw[N]; int pri[N]; bitset<N> vis; void Euler() { int num = 0; pw[0] = 0, pw[1] = 1; for (int i = 2; i <= n; i++) { if (!vis.test(i)) { pw[i] = qpow(i, n + 1); pri[num++] = i; } for (int *p = pri, *_p = pri + num, x; p != _p && (x = *p * i) <= n; p++) { vis.set(x); pw[x] = pw[i] * pw[*p]; if (!(i % *p)) { break; } } } } int main() { scanf("%d", &n); get_g(); Euler(); Zi ans = g[0] + g[1] * (n + 1); for (int i = 2; i <= n; i++) { ans += (pw[i] - 1) * Inv[i - 1] * g[i]; } printf("%d\n", ans.v); return 0; }