BZOJ4555[HEOI2016/TJOI2016]求和
題目鏈接
洛谷
BZOJ
前置知識
第二類斯特林?jǐn)?shù)
含義
\(S_n^m\)表示將\(n\)個互不相同的元素劃分為\(m\)個非空集合的方案數(shù)
遞推式
\[ S_n^m = S_{n - 1}^{m - 1} + m \cdot S_{n - 1}^m \]
通項公式
\[ S_n^m = \frac{1}{m!} \cdot \sum_{k = 0}^m (-1)^k \cdot {m \choose k} \cdot (m - k)^n \]
NTT
類似于\(FFT\),在固定模數(shù)的情況下,可以將單位根用模數(shù)\(P\)的原根的\(\frac{P - 1}{n}\)次冪代替,避免復(fù)數(shù)運算掉精度
還是放個鏈接吧:NTT詳解
解析
首先\(j\)的上界可以擴展到\(n\),因為\(j > i\)的時候\(S(i,j) = 0\)
后兩項都只和\(j\)有關(guān),所以換一下枚舉順序,把這兩項提出來:
\[ f(n) = \sum_{j = 0}^n 2^j \cdot (j!) \cdot \sum_{i = 0}^n S(i, j) \]
你看那個\(S(i,j)\)就很不友好,我們直接把它干掉,用通項替換:
\[ f(n) = \sum_{j = 0}^n 2^j \cdot (j!) \cdot \sum_{i = 0}^n \frac{1}{j!} \cdot \sum_{k = 0}^j (-1)^k \cdot \frac{j!}{k! \cdot (j - k)!} \cdot (j - k)^i \]
然后一波化簡可得:
\[ f(n) = \sum_{j = 0}^n 2^j \cdot (j!) \cdot \sum_{i = 0}^n \sum_{k = 0}^j (-1)^k \cdot \frac{1}{k! \cdot (j - k)!} \cdot (j - k)^i \]
我們把后面那一坨提出來,令:
\[ g(j) = \sum_{i = 0}^n \sum_{k = 0}^j (-1)^k \cdot \frac{1}{k! \cdot (j - k)!} \cdot (j - k)^i \\ = \sum_{k = 0}^j \frac{(-1)^k}{k!} \cdot \frac{\sum_{i = 0}^n (j - k)^i}{(j - k)!} \]
再令:
\[ a(i) = \frac{(-1)^i}{i!},b(i) = \frac{\sum_{k = 0}^n i^k}{i!} = \frac{i^{k + 1} - 1}{(i - 1) \cdot i!} \]
容易發(fā)現(xiàn)\(g\)就是\(a\)和\(b\)的卷積
特別地,\(b(0) = 1, b(1) = n + 1\)
那么用\(NTT\)或者\(FFT\)什么的求出\(g\)后,答案就是\(f(n) = \sum_{i = 0}^n 2^i \cdot (i!) \cdot g(i)\)
代碼
我寫的\(NTT\),然而忘了開\(4n\)的數(shù)組\(RE\)了\(3\)發(fā)。。。。。
#include <cstdio> #include <cstring> #include <iostream> #define MAXN 100005typedef long long LL; const LL mod = 998244353ll; LL N, g[MAXN << 2], a[MAXN << 2], b[MAXN << 2], fact[MAXN]; LL G = 3, ans;LL qpower(LL, LL); void NTT(LL *, int, int); inline LL inverse(LL x) { return qpower(x, mod - 2); } int main() {std::ios::sync_with_stdio(false);std::cin >> N;fact[0] = 1;for (int i = 1; i <= N; ++i) fact[i] = fact[i - 1] * i % mod;for (int i = 0; i <= N; ++i) a[i] = ((i & 1) ? -1 : 1) * inverse(fact[i]);b[0] = 1, b[1] = N + 1;for (int i = 2; i <= N; ++i) b[i] = (qpower(i, N + 1) - 1) * inverse(fact[i]) % mod * inverse(i - 1) % mod;int sz = 1;while (sz <= (N << 1)) sz <<= 1;NTT(a, sz, 1);NTT(b, sz, 1);for (int i = 0; i < sz; ++i) g[i] = a[i] * b[i] % mod;NTT(g, sz, -1);LL pow2 = 1;for (int i = 0; i <= N; ++i, pow2 = (pow2 << 1) % mod)ans = (ans + pow2 * fact[i] % mod * g[i] % mod) % mod;std::cout << ans << std::endl;return 0; } LL qpower(LL x, LL y) {LL res = 1;while (y) {if (y & 1) (res *= x) %= mod;(x *= x) %= mod;y >>= 1;}return res; } void NTT(LL *arr, int sz, int type) {int rev[MAXN << 2]; rev[0] = 0;for (int i = 1; i < sz; ++i) {rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (sz >> 1) : 0);if (rev[i] > i) std::swap(arr[i], arr[rev[i]]);}for (int len = 2, half = 1; len <= sz; len <<= 1, half <<= 1) {LL wn = qpower(G, (mod - 1) / len);if (type == -1) wn = inverse(wn);for (int i = 0; i < sz; i += len) {LL w = 1;for (int j = 0; j < half; ++j, w = w * wn % mod) {LL tmp1 = arr[i + j], tmp2 = arr[i + half + j] * w % mod;arr[i + j] = tmp1 + tmp2; if (arr[i + j] >= mod) arr[i + j] -= mod;arr[i + half + j] = tmp1 - tmp2; if (arr[i + half + j] < 0) arr[i + half + j] += mod;}}}if (type == -1) {LL inv = inverse(sz);for (int i = 0; i < sz; ++i) arr[i] = arr[i] * inv % mod;} } //Rhein_E轉(zhuǎn)載于:https://www.cnblogs.com/Rhein-E/p/10439527.html
總結(jié)
以上是生活随笔為你收集整理的BZOJ4555[HEOI2016/TJOI2016]求和的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux keepalived
- 下一篇: Maven整合SSM测试