题解:CF961G Partitions
masonxiong · · 题解
一种力大砖飞的做法。
考虑拆贡献:对于一个
同时,我们需要把剩下的
根据乘法原理,
-
解释:枚举每个
w_i 以及所有可能的子集大小s ,将其贡献乘上方案数并求和。 -
将与内层循环无关的项
w_i 依据乘法分配律提前。
这个式子还可以简化,但是已经可以直接力大砖飞解掉了。组合数可以预处理阶乘并
我们注意到这里斯特林数的
:::info[code]
#include <bits/extc++.h>
namespace {
constexpr unsigned Modulus = 1E9 + 7;
std::vector<std::complex<double>> factors;
auto DIF(std::vector<std::complex<double>>& A) -> void {
for (auto n = unsigned(A.size()), m = n >> 1; m != 0; m >>= 1) {
for (auto s = m << 1, o = n / s, i = 0U; i != n; i += s) {
for (auto j = 0U; j != m; ++j) {
auto x = A[i + j], y = A[i + j + m];
A[i + j] = x + y, A[i + j + m] = (x - y) * factors[j * o];
}
}
}
}
auto DIT(std::vector<std::complex<double>>& A) -> void {
for (auto n = unsigned(A.size()), m = 1U; m != n; m <<= 1) {
for (auto s = m << 1, o = n / s, i = 0U; i != n; i += s) {
for (auto j = 0U; j != m; ++j) {
auto x = A[i + j], y = A[i + j + m] * std::conj(factors[j * o]);
A[i + j] = x + y, A[i + j + m] = x - y;
}
}
}
}
auto multiplies(std::vector<unsigned> P, std::vector<unsigned> Q) -> std::vector<unsigned> {
auto s = P.size() + Q.size();
--s;
auto n = unsigned(std::__bit_ceil(s));
auto m = unsigned(std::__bit_width(n) - 1);
factors.resize(n >> 1);
for (auto i = 0U; i != n >> 1; ++i) {
auto Pi = std::acos(-1);
factors[i] = std::polar(1.0, -2.0 * Pi * i / n);
}
std::vector<unsigned> reversed(n);
for (auto i = 1U; i != n; ++i) {
reversed[i] = reversed[i >> 1] >> 1;
reversed[i] |= (i & 1) << (m - 1);
}
std::vector<std::complex<double>> A(n), B(n), C(n), D(n);
for (auto i = 0U; i != P.size(); ++i) {
auto x = P[i] % Modulus;
A[i] = {double(x & 0xFFFF), double(x >> 16)};
}
for (auto i = 0U; i != Q.size(); ++i) {
auto x = Q[i] % Modulus;
B[i] = {double(x & 0xFFFF), double(x >> 16)};
}
DIF(A);
DIF(B);
for (auto o = 0U; o != n; ++o) {
auto i = reversed[o];
auto j = reversed[(n - o) & (n - 1)];
auto u = (A[i] + std::conj(A[j])) * 0.5;
auto v = (A[i] - std::conj(A[j])) * std::complex(0.0, -0.5);
auto x = (B[i] + std::conj(B[j])) * 0.5;
auto y = (B[i] - std::conj(B[j])) * std::complex(0.0, -0.5);
C[i] = u * x + std::complex<double>(0.0, 1.0) * v * y;
D[i] = u * y + v * x;
}
DIT(C);
DIT(D);
std::vector<unsigned> result(s);
for (auto i = 0U; i != s; ++i) {
auto u = std::uint64_t(std::int64_t(std::llround(C[i].real() / n)) % Modulus + Modulus) % Modulus;
auto v = std::uint64_t(std::int64_t(std::llround(D[i].real() / n)) % Modulus + Modulus) % Modulus;
auto w = std::uint64_t(std::int64_t(std::llround(C[i].imag() / n)) % Modulus + Modulus) % Modulus;
result[i] = unsigned((u + (v << 16) + (w << 32)) % Modulus);
}
return result;
}
}
auto main() -> int {
std::cin.tie(nullptr)->sync_with_stdio(false);
unsigned n, k;
std::cin >> n >> k;
std::vector<unsigned> W(n);
std::copy_n(std::istream_iterator<unsigned>(std::cin), n, W.data());
std::vector<unsigned> stirling(n);
const auto required = n - --k;
auto product = [required](auto& self, auto l, auto r) -> std::vector<unsigned> {
switch (auto s = r - l) {
case 0: return {1};
case 1: return {1, Modulus - l};
default: {
const auto m = (l + r) / 2;
auto result = multiplies(self(self, l, m), self(self, m, r));
if (result.size() > required) result.resize(required);
return result;
}
}
};
const auto denominator = product(product, 1U, k + 1);
std::vector<unsigned> inverse{1};
while (inverse.size() < required) {
const auto size = std::min<std::size_t>(inverse.size() * 2, required);
std::vector prefix(denominator.data(), denominator.data() + std::min(denominator.size(), size));
auto correction = multiplies(prefix, inverse);
correction.resize(size);
for (auto& x : correction) x = x == 0 ? 0 : Modulus - x;
correction[0] = (correction[0] + 2) % Modulus;
(inverse = multiplies(inverse, correction)).resize(size);
}
std::copy(inverse.begin(), inverse.end(), stirling.begin() + k);
std::vector factorial(n, 0ULL);
for (auto i = factorial[0] = 1; i != n; ++i)
factorial[i] = factorial[i - 1] * i % Modulus;
auto power = [](auto v) {
auto o = 1ULL;
for (auto e = Modulus - 2; e; (e & 1) && (o = o * v % Modulus), v = v * v % Modulus, e >>= 1);
return o;
};
auto sum = 0ULL;
for (auto s = 1ULL; s <= n - k; ++s) {
auto binomial = factorial.back() % Modulus * power(factorial[s - 1]) % Modulus * power(factorial[n - s]) % Modulus;
sum = (sum + s * stirling[n - s] % Modulus * binomial % Modulus) % Modulus;
}
sum *= std::accumulate(W.begin(), W.end(), 0ULL) % Modulus;
std::cout << sum % Modulus << '\n';
constexpr auto Anon = 0x0908, Soyo = 0x0527, Tomori = 0x1122, Taki = 0x0809, Rana = 0x0222;
std::clog << "Duration = " << std::clock() << " clocks\n";
return Anon & Soyo & Tomori & Taki & Rana;
}
:::