Description
给定 n,k,求:
i=1∑n(in)×ik
1≤k≤5000,1≤n≤109。
Solution
看到那个 ik 很不爽,但是 k 很小,考虑用斯特林数改写一下:
ik=j=0∑k(ji){kj}⋅j!
代回原式得:
=====i=0∑n(in)⋅j=0∑k(ji){kj}j!j=0∑kj!{kj}⋅i=0∑n(in)(ji)j=0∑kj!{kj}⋅i=j∑ni!(n−i)!n!⋅j!(i−j)!i!n!j=0∑k{kj}⋅i=j∑n(n−j)!(i−jn−j)n!j=0∑k(n−j)!1{kj}i=0∑n−j(in−j)n!j=0∑k(n−j)!2n−j⋅{kj}
于是直接预处理出斯特林数即可做到 O(k2+klogn),如果用卷积预处理的话就可以做到 O(klogk+klogn)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <bits/stdc++.h>
using i64 = int64_t;
const int kMod = 1e9 + 7;
int s[5005][5005];
int qpow(int bs, int idx = kMod - 2) { int ret = 1; for (; idx; idx >>= 1, bs = (i64)bs * bs % kMod) if (idx & 1) ret = (i64)ret * bs % kMod; return ret; }
void dickdreamer() { int n, k, ans = 0; std::cin >> n >> k; s[0][0] = 1; for (int i = 1; i <= k; ++i) { for (int j = 1; j <= i; ++j) { s[i][j] = (s[i - 1][j - 1] + (i64)j * s[i - 1][j] % kMod) % kMod; } } for (int i = 0, c = 1; i <= std::min(n, k); ++i) { ans = (ans + (i64)s[k][i] * c % kMod * qpow(2, n - i) % kMod) % kMod; c = (i64)c * (n - i) % kMod; } std::cout << ans << '\n'; }
int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; while (T--) dickdreamer(); return 0; }
|