QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#561651 | #6196. Minimum Element Problem | ucup-team4435 | AC ✓ | 183ms | 33068kb | C++20 | 35.9kb | 2024-09-13 04:53:00 | 2024-09-13 04:53:00 |
Judging History
answer
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
#define all(a) begin(a), end(a)
#define len(a) int((a).size())
#ifdef LOCAL
#include "debug.h"
#else
#define dbg(...)
#define dprint(...)
#define debug if constexpr (false)
#define draw_tree(...)
#define draw_array(...)
#endif // LOCAL
/*
! WARNING: MOD must be prime.
! WARNING: MOD must be less than 2^30.
* Use .get() to get the stored value.
*/
template<uint32_t mod>
class montgomery {
static_assert(mod < uint32_t(1) << 30, "mod < 2^30");
using mint = montgomery<mod>;
private:
uint32_t value;
static constexpr uint32_t inv_neg_mod = []() {
uint32_t x = mod;
for (int i = 0; i < 4; ++i) {
x *= uint32_t(2) - mod * x;
}
return -x;
}();
static_assert(mod * inv_neg_mod == -1);
static constexpr uint32_t neg_mod = (-uint64_t(mod)) % mod;
static uint32_t reduce(const uint64_t &value) {
return (value + uint64_t(uint32_t(value) * inv_neg_mod) * mod) >> 32;
}
inline static const mint ONE = mint(1);
public:
montgomery() : value(0) {}
montgomery(const mint &x) : value(x.value) {}
template<typename T, typename U = std::enable_if_t<std::is_integral<T>::value>>
montgomery(const T &x) : value(!x ? 0 : reduce(int64_t(x % int32_t(mod) + int32_t(mod)) * neg_mod)) {}
static constexpr uint32_t get_mod() {
return mod;
}
uint32_t get() const {
auto real_value = reduce(value);
return real_value < mod ? real_value : real_value - mod;
}
template<typename T>
mint power(T degree) const {
degree = (degree % int32_t(mod - 1) + int32_t(mod - 1)) % int32_t(mod - 1);
mint prod = 1, a = *this;
for (; degree > 0; degree >>= 1, a *= a)
if (degree & 1)
prod *= a;
return prod;
}
mint inv() const {
return power(-1);
}
mint& operator=(const mint &x) {
value = x.value;
return *this;
}
mint& operator+=(const mint &x) {
if (int32_t(value += x.value - (mod << 1)) < 0) {
value += mod << 1;
}
return *this;
}
mint& operator-=(const mint &x) {
if (int32_t(value -= x.value) < 0) {
value += mod << 1;
}
return *this;
}
mint& operator*=(const mint &x) {
value = reduce(uint64_t(value) * x.value);
return *this;
}
mint& operator/=(const mint &x) {
return *this *= x.inv();
}
friend mint operator+(const mint &x, const mint &y) {
return mint(x) += y;
}
friend mint operator-(const mint &x, const mint &y) {
return mint(x) -= y;
}
friend mint operator*(const mint &x, const mint &y) {
return mint(x) *= y;
}
friend mint operator/(const mint &x, const mint &y) {
return mint(x) /= y;
}
mint& operator++() {
return *this += ONE;
}
mint& operator--() {
return *this -= ONE;
}
mint operator++(int) {
mint prev = *this;
*this += ONE;
return prev;
}
mint operator--(int) {
mint prev = *this;
*this -= ONE;
return prev;
}
mint operator-() const {
return mint(0) - *this;
}
bool operator==(const mint &x) const {
return get() == x.get();
}
bool operator!=(const mint &x) const {
return get() != x.get();
}
bool operator<(const mint &x) const {
return get() < x.get();
}
template<typename T>
explicit operator T() {
return get();
}
friend std::istream& operator>>(std::istream &in, mint &x) {
std::string s;
in >> s;
x = 0;
bool neg = s[0] == '-';
for (const auto c : s)
if (c != '-')
x = x * 10 + (c - '0');
if (neg)
x *= -1;
return in;
}
friend std::ostream& operator<<(std::ostream &out, const mint &x) {
return out << x.get();
}
static int32_t primitive_root() {
if constexpr (mod == 1'000'000'007)
return 5;
if constexpr (mod == 998'244'353)
return 3;
if constexpr (mod == 786433)
return 10;
static int root = -1;
if (root != -1)
return root;
std::vector<int> primes;
int value = mod - 1;
for (int i = 2; i * i <= value; i++)
if (value % i == 0) {
primes.push_back(i);
while (value % i == 0)
value /= i;
}
if (value != 1)
primes.push_back(value);
for (int r = 2;; r++) {
bool ok = true;
for (auto p : primes)
if ((mint(r).power((mod - 1) / p)).get() == 1) {
ok = false;
break;
}
if (ok)
return root = r;
}
}
};
// constexpr uint32_t MOD = 1'000'000'007;
constexpr uint32_t MOD = 998'244'353;
using mint = montgomery<MOD>;
/*
! WARNING: MOD must be prime.
* Define modular int class above it.
* No need to run any init function, it dynamically resizes the data.
*/
namespace combinatorics {
std::vector<mint> fact_, ifact_, inv_;
void resize_data(int size) {
if (fact_.empty()) {
fact_ = {mint(1), mint(1)};
ifact_ = {mint(1), mint(1)};
inv_ = {mint(0), mint(1)};
}
for (int pos = fact_.size(); pos <= size; pos++) {
fact_.push_back(fact_.back() * mint(pos));
inv_.push_back(-inv_[MOD % pos] * mint(MOD / pos));
ifact_.push_back(ifact_.back() * inv_[pos]);
}
}
struct combinatorics_info {
std::vector<mint> &data;
combinatorics_info(std::vector<mint> &data) : data(data) {}
mint operator[](int pos) {
if (pos >= static_cast<int>(data.size())) {
resize_data(pos);
}
return data[pos];
}
} fact(fact_), ifact(ifact_), inv(inv_);
// From n choose k.
// O(max(n)) in total.
mint choose(int n, int k) {
if (n < k || k < 0 || n < 0) {
return mint(0);
}
return fact[n] * ifact[k] * ifact[n - k];
}
// From n choose k.
// O(min(k, n - k)).
mint choose_slow(int64_t n, int64_t k) {
if (n < k || k < 0 || n < 0) {
return mint(0);
}
k = std::min(k, n - k);
mint result = 1;
for (int i = k; i >= 1; i--) {
result *= (n - i + 1);
result *= inv[i];
}
return result;
}
// Number of balanced bracket sequences with n open and m closing brackets.
mint catalan(int n, int m) {
if (m > n || m < 0) {
return mint(0);
}
return choose(n + m, m) - choose(n + m, m - 1);
}
// Number of balanced bracket sequences with n open and closing brackets.
mint catalan(int n) {
return catalan(n, n);
}
} // namespace combinatorics
using namespace combinatorics;
/*
! WARNING: (MOD - 1) must be divisible by (2n), where n is max degree of polynomials.
* Include static_modular_int or montgomery (faster) to use it.
* Don't need to care about precomputing primitive root.
* Use it like std::vector<mint> with extra methods.
*/
template<typename mint>
class polynom_t : public std::vector<mint> {
public:
static constexpr int RANK = __builtin_ctz(mint::get_mod() - 1);
static_assert(RANK >= 15, "MOD doesn't seem fft-friendly.");
using value_type = mint;
using std::vector<mint>::empty;
using std::vector<mint>::back;
using std::vector<mint>::pop_back;
using std::vector<mint>::size;
using std::vector<mint>::clear;
using std::vector<mint>::begin;
using std::vector<mint>::end;
private:
static constexpr int EVAL_BRUTE_SIZE = 1 << 4;
static constexpr int MUL_MIN_CUT = 20;
static constexpr int MUL_MAX_CUT = 1 << 6;
static constexpr int DIV_N_CUT = 1 << 7;
static constexpr int DIV_M_CUT = 1 << 6;
static constexpr int INV_BRUTE_FORCE_SIZE = 1 << 3;
class fft_precalc {
private:
std::vector<mint> inv_{0, 1};
public:
mint root;
// roots[x] = root.power((MOD - 1) / 2^x)
// inv_roots[x] = roots[x].inv()
std::array<mint, RANK> roots, inv_roots;
// inv_n[x] = 2^{-x}
std::array<mint, RANK> inv_l;
// r_transition[x] = root.power((MOD - 1) * (3 - 2^{x + 1}) / 2^{x + 2})
// inv_r_transition[x] = r_transition[x].inv()
std::array<mint, RANK> r_transition, inv_r_transition;
fft_precalc() {
root = mint::primitive_root();
for (int x = 0; x < RANK; x++) {
roots[x] = mint(root).power((mint::get_mod() - 1) >> x);
inv_roots[x] = roots[x].inv();
inv_l[x] = mint(1 << x).inv();
r_transition[x] = root.power(((mint::get_mod() - 1) >> (x + 2)) * (3 + (1 << (x + 1))));
inv_r_transition[x] = r_transition[x].inv();
}
}
mint inv(int x) {
for (int i = inv_.size(); i <= x; i++) {
inv_.push_back(-inv_[mint::get_mod() % i] * mint(mint::get_mod() / i));
}
return inv_[x];
}
};
inline static fft_precalc fft_data;
public:
/*
* Let r be the primitive root of the given MOD.
* Let rev(i) be the reversed i as a binary mask of size log(n).
* Let R[i] = r.power((MOD - 1) / a.size() * rev(i)).
* It replaces a[i] with a.eval(R[i]).
*/
static void fft(polynom_t<mint> &a) {
assert(!a.empty());
int n = a.size(), l = __builtin_ctz(n);
for (int len = 0; len < l; len++) {
int m = n >> (len + 1);
mint r = 1;
for (int i = 0; i < (1 << len); i++) {
// rot = r^((MOD - 1) / n * rev(2 * i))
int id = i << (l - len);
for (int j = 0; j < m; j++) {
auto u = a[id + j];
auto v = a[id + j + m] * r;
a[id + j] = u + v;
a[id + j + m] = u - v;
}
if (i + 1 < (1 << len)) {
r *= fft_data.r_transition[__builtin_ctz(~i)];
}
}
}
}
// inv_fft(fft(a)) = a
static void inv_fft(polynom_t<mint> &a) {
assert(!a.empty());
int n = a.size(), l = __builtin_ctz(n);
for (int len = l - 1; len >= 0; len--) {
int m = n >> (len + 1);
mint ir = 1;
for (int i = 0; i < (1 << len); i++) {
int id = i << (l - len);
for (int j = 0; j < m; j++) {
auto u = a[id + j];
auto v = a[id + j + m];
a[id + j] = u + v;
a[id + j + m] = (u - v) * ir;
}
if (i + 1 < (1 << len)) {
ir *= fft_data.inv_r_transition[__builtin_ctz(~i)];
}
}
}
for (auto &value : a) {
value *= fft_data.inv_l[l];
}
}
private:
// Completes fft assuming that a is the right half of the polynomial after the first iteration of the fft.
static void right_half_fft(polynom_t<mint> &a) {
assert(!a.empty());
int n = a.size(), l = __builtin_ctz(n);
for (int len = 0; len < l; len++) {
int m = n >> (len + 1);
mint r = fft_data.roots[len + 2];
for (int i = 0; i < (1 << len); i++) {
int id = i << (l - len);
for (int j = 0; j < m; j++) {
auto u = a[id + j];
auto v = a[id + j + m] * r;
a[id + j] = u + v;
a[id + j + m] = u - v;
}
if (i + 1 < (1 << len)) {
r *= fft_data.r_transition[__builtin_ctz(~i)];
}
}
}
}
// inv_right_half_fft(right_half_fft(a)) = a
static void inv_right_half_fft(polynom_t<mint> &a) {
assert(!a.empty());
int n = a.size(), l = __builtin_ctz(n);
for (int len = l - 1; len >= 0; len--) {
int m = n >> (len + 1);
mint ir = fft_data.inv_roots[len + 2];
for (int i = 0; i < (1 << len); i++) {
int id = i << (l - len);
for (int j = 0; j < m; j++) {
auto u = a[id + j];
auto v = a[id + j + m];
a[id + j] = u + v;
a[id + j + m] = (u - v) * ir;
}
if (i + 1 < (1 << len)) {
ir *= fft_data.inv_r_transition[__builtin_ctz(~i)];
}
}
}
for (auto &value : a) {
value *= fft_data.inv_l[l];
}
}
class multipoint_evaluation_tree {
private:
int n_points, l;
std::vector<polynom_t<mint>> segtree;
public:
multipoint_evaluation_tree(int n, const std::vector<mint> &points) : n_points(points.size()), l(1) {
while ((1 << l) < n) {
l++;
}
polynom_t<mint> aux;
aux.reserve(1 << l);
segtree.assign(l + 1, polynom_t<mint>(1 << (l + 1)));
for (int i = 0; i < (1 << l); i++) {
aux = {i < n_points ? -points[i] : 0, 1};
fft(aux);
segtree[0][i << 1] = aux[0];
segtree[0][i << 1 | 1] = aux[1];
}
for (int len = 0; len < l; len++) {
aux.resize(1 << (len + 1));
for (int i = 0; i < (1 << (l + 1)); i += (1 << (len + 2))) {
for (int j = 0; j < static_cast<int>(aux.size()); j++) {
aux[j] = segtree[len][i + j] * segtree[len][i + j + aux.size()];
}
if (len + 1 < l) {
std::copy(aux.begin(), aux.end(), segtree[len + 1].begin() + i);
inv_fft(aux);
aux[0] -= 2;
right_half_fft(aux);
std::copy(aux.begin(), aux.end(), segtree[len + 1].begin() + i + aux.size());
} else {
inv_fft(aux);
aux[0]--;
std::copy(aux.begin(), aux.end(), segtree[len + 1].begin() + i);
segtree[len + 1][1 << (len + 1)]++;
}
}
}
}
std::vector<mint> evaluate(polynom_t<mint> f) const {
if (static_cast<int>(f.size()) > (1 << l)) {
f %= segtree[l];
}
assert(static_cast<int>(f.size()) <= (1 << l));
f.resize(1 << (l + 1));
std::rotate(f.begin(), std::prev(f.end()), f.end());
fft(f);
auto g = segtree[l];
std::reverse(g.begin(), g.begin() + 1 + (1 << l));
g.resize(1 << l);
g = g.inv(1 << l);
std::reverse(g.begin(), g.end());
g.resize(1 << (l + 1));
fft(g);
for (int i = 0; i < (1 << (l + 1)); i++) {
g[i] *= f[i];
}
polynom_t<mint> aux;
aux.reserve(1 << l);
for (int len = l - 1; len >= 0; len--) {
aux.resize(1 << (len + 1));
for (int i = 0; i < (1 << (l + 1)); i += (1 << (len + 2))) {
for (int j = 0; j < static_cast<int>(aux.size()); j++) {
aux[j] = g[i + j + (1 << (len + 1))];
}
inv_right_half_fft(aux);
fft(aux);
std::copy(aux.begin(), aux.end(), g.begin() + i + (1 << (len + 1)));
for (int j = 0; j < (1 << (len + 1)); j++) {
auto x = g[i + j] - g[i + j + (1 << (len + 1))];
g[i + j + (1 << (len + 1))] = x * segtree[len][i + j];
g[i + j] = x * segtree[len][i + j + (1 << (len + 1))];
}
}
}
std::vector<mint> eval(n_points);
for (int i = 0; i < n_points; i++) {
eval[i] = (g[2 * i] - g[2 * i + 1]) * fft_data.inv_l[l + 1];
}
return eval;
}
polynom_t<mint> interpolate(const std::vector<mint> &y) const {
auto prod = segtree[l];
prod.erase(prod.begin(), prod.begin() + ((1 << l) - n_points));
auto values = evaluate(prod.derivative());
polynom_t<mint> aux;
aux.reserve(1 << l);
polynom_t<mint> result(1 << (l + 1));
for (int i = 0; i < (1 << l); i++) {
aux = {i < n_points ? y[i] / values[i] : 0, 0};
fft(aux);
result[i << 1] = aux[0];
result[i << 1 | 1] = aux[1];
}
polynom_t<mint> next(1 << (l + 1));
for (int len = 0; len < l; len++) {
aux.resize(1 << (len + 1));
for (int i = 0; i < (1 << (l + 1)); i += (1 << (len + 2))) {
for (int j = 0; j < (1 << (len + 1)); j++) {
aux[j] = segtree[len][i + j] * result[i + j + aux.size()]
+ segtree[len][i + j + aux.size()] * result[i + j];
}
if (len + 1 < l) {
std::copy(aux.begin(), aux.end(), next.begin() + i);
inv_fft(aux);
right_half_fft(aux);
std::copy(aux.begin(), aux.end(), next.begin() + i + (1 << (len + 1)));
} else {
inv_fft(aux);
std::copy(aux.begin(), aux.end(), next.begin());
}
}
result.swap(next);
}
result.erase(result.begin(), result.begin() + ((1 << l) - n_points));
return result.resize(n_points);
}
};
public:
polynom_t() : std::vector<mint>() {}
polynom_t(size_t n, mint value = 0) : std::vector<mint>(n, value) {}
polynom_t(std::initializer_list<mint> values) : std::vector<mint>(values.begin(), values.end()) {}
template<typename Iterator>
polynom_t(Iterator first, Iterator last) : std::vector<mint>(first, last) {}
polynom_t<mint>& resize(int n) {
std::vector<mint>::resize(n);
return *this;
}
// Removes extra zeroes.
void normalize() {
while (!empty() && back() == mint(0)) {
pop_back();
}
}
// Returns -1 if all coefficients are zeroes (not O(1)!).
int degree() const {
int deg = static_cast<int>(size()) - 1;
while (deg >= 0 && (*this)[deg] == mint(0)) {
deg--;
}
return deg;
}
mint eval(const mint &x) const {
mint power = 1, value = 0;
for (int i = 0; i < static_cast<int>(size()); i++, power *= x) {
value += (*this)[i] * power;
}
return value;
}
// Calculates eval at the given points.
// O(n log^2).
std::vector<mint> multipoint_evaluation(const std::vector<mint> &points) const {
if (std::min(size(), points.size()) <= EVAL_BRUTE_SIZE) {
std::vector<mint> eval(points.size());
for (int i = 0; i < static_cast<int>(points.size()); i++) {
eval[i] = this->eval(points[i]);
}
return eval;
}
return multipoint_evaluation_tree(std::max(size(), points.size()), points).evaluate(*this);
}
// Interpolates polynomial f, such that f(x[i]) = y[i].
// O(n log^2).
static polynom_t<mint> interpolate(const std::vector<mint> &x, const std::vector<mint> &y) {
assert(x.size() == y.size());
return multipoint_evaluation_tree(x.size(), x).interpolate(y);
}
polynom_t<mint> operator-() const {
return polynom_t(*this) * mint(-1);
}
polynom_t<mint>& operator+=(const polynom_t<mint> &another) {
if (size() < another.size()) {
resize(another.size());
}
for (int i = 0; i < static_cast<int>(another.size()); i++) {
(*this)[i] += another[i];
}
return *this;
}
polynom_t<mint>& operator-=(const polynom_t<mint> &another) {
if (size() < another.size()) {
resize(another.size());
}
for (int i = 0; i < static_cast<int>(another.size()); i++) {
(*this)[i] -= another[i];
}
return *this;
}
polynom_t<mint>& operator*=(const polynom_t<mint> &another) {
if (empty() || another.empty()) {
clear();
return *this;
}
if (std::min(size(), another.size()) <= MUL_MIN_CUT
|| std::max(size(), another.size()) <= MUL_MAX_CUT) {
polynom_t<mint> product(int(size() + another.size()) - 1);
for (int i = 0; i < static_cast<int>(size()); i++) {
for (int j = 0; j < static_cast<int>(another.size()); j++) {
product[i + j] += (*this)[i] * another[j];
}
}
product.swap(*this);
return *this;
}
int real_size = static_cast<int>(size() + another.size()) - 1, n = 1;
while (n < real_size) {
n <<= 1;
}
if ((*this) == another) {
resize(n);
fft(*this);
for (int i = 0; i < n; i++) {
(*this)[i] *= (*this)[i];
}
} else {
resize(n);
polynom_t b = another;
b.resize(n);
fft(*this), fft(b);
for (int i = 0; i < n; i++) {
(*this)[i] *= b[i];
}
}
inv_fft(*this);
return resize(real_size);
}
// Division with remainder.
// O(n log).
polynom_t<mint>& operator/=(const polynom_t<mint> &another) {
polynom_t<mint> a(*this), b(another);
a.normalize(), b.normalize();
assert(!b.empty());
int n = a.size(), m = b.size();
if (n < m) {
return *this = {};
}
if (n <= DIV_N_CUT || m <= DIV_M_CUT) {
polynom_t<mint> quotient(n - m + 1);
mint inv_b = mint(1) / b.back();
for (int i = n - 1; i >= m - 1; i--) {
int pos = i - m + 1;
quotient[pos] = a[i] * inv_b;
for (int j = 0; j < m; j++) {
a[pos + j] -= b[j] * quotient[pos];
}
}
quotient.normalize();
return *this = quotient;
}
std::reverse(a.begin(), a.end());
std::reverse(b.begin(), b.end());
polynom_t<mint> quotient = a * b.inv(n - m + 1);
quotient.resize(n - m + 1);
std::reverse(quotient.begin(), quotient.end());
quotient.normalize();
return *this = quotient;
}
// O(n log).
polynom_t<mint>& operator%=(const polynom_t<mint> &another) {
*this -= (*this) / another * another;
normalize();
return *this;
}
// Returns derivative.
// O(n).
polynom_t<mint> derivative() const {
polynom_t<mint> der(std::max(0, static_cast<int>(size()) - 1));
for (int i = 0; i < static_cast<int>(der.size()); i++) {
der[i] = mint(i + 1) * (*this)[i + 1];
}
return der;
}
// Returns integral.
// O(n).
polynom_t<mint> integral(const mint &constant = mint(0)) const {
polynom_t<mint> in(size() + 1);
in[0] = constant;
for (int i = 1; i < static_cast<int>(in.size()); i++) {
in[i] = (*this)[i - 1] * fft_data.inv(i);
}
return in;
}
// Returns p^{-1} modulo x^{degree}.
// O(n log).
polynom_t<mint> inv(int degree) const {
assert(!empty() && (*this)[0] != mint(0) && "polynom is not invertable");
int result_size = 1;
while (result_size < degree) {
result_size <<= 1;
}
polynom_t<mint> inv(result_size);
inv[0] = (*this)[0].inv();
int brute_calculation = std::min(degree, INV_BRUTE_FORCE_SIZE);
mint start_inv = (*this)[0].inv();
polynom_t<mint> have(brute_calculation);
for (int i = 0; i < brute_calculation; i++) {
inv[i] = ((i == 0 ? 1 : 0) - have[i]) * start_inv;
int steps = std::min<int>(size(), have.size() - i);
for (int j = 0; j < steps; j++) {
have[i + j] += inv[i] * (*this)[j];
}
}
polynom_t<mint> this_copy, inv_copy;
this_copy.reserve(result_size);
inv_copy.reserve(result_size);
for (int power = brute_calculation; power < degree; power <<= 1) {
this_copy.resize(power << 1);
std::fill(this_copy.begin() + std::min<int>(size(), power << 1), this_copy.end(), 0);
std::copy(begin(), begin() + std::min<int>(size(), power << 1), this_copy.begin());
inv_copy.resize(power << 1);
std::copy(inv.begin(), inv.begin() + power, inv_copy.begin());
fft(this_copy);
fft(inv_copy);
for (int i = 0; i < (power << 1); i++) {
this_copy[i] *= inv_copy[i];
}
inv_fft(this_copy);
std::fill(this_copy.begin(), this_copy.begin() + power, 0);
fft(this_copy);
for (int i = 0; i < (power << 1); i++) {
this_copy[i] *= inv_copy[i];
}
inv_fft(this_copy);
for (int i = power; i < (power << 1); i++) {
inv[i] = -this_copy[i];
}
}
return inv.resize(degree);
}
// Returns log(p) modulo x^{degree}.
// O(n log).
polynom_t<mint> log(int degree) const {
assert(!empty() && (*this)[0] == mint(1) && "log is not defined");
return (derivative().resize(std::min<int>(degree, size())) * inv(degree)).resize(degree).integral(mint(0)).resize(degree);
}
// Returns exp(p) modulo x^{degree}.
// O(n log).
polynom_t<mint> exp(int degree) const {
assert(!empty() && (*this)[0] == mint(0) && "exp is not defined");
int result_size = 1;
while (result_size < degree) {
result_size <<= 1;
}
polynom_t<mint> exp, exp_fft, inv_exp, inv_exp_fft;
exp = exp_fft = inv_exp = inv_exp_fft = {1};
polynom_t<mint> h(1), q(1);
auto diff = derivative().resize(result_size);
for (int power = 1; power < degree; power <<= 1) {
exp_fft = polynom_t<mint>(exp).resize(power << 1);
fft(exp_fft);
for (int i = 0; i < power; i++) {
h[i] = exp_fft[i] * inv_exp_fft[i];
}
inv_fft(h);
std::fill(h.begin(), h.begin() + ((power + 1) >> 1), 0);
fft(h);
for (int i = 0; i < power; i++) {
h[i] *= -inv_exp_fft[i];
}
inv_fft(h);
for (int i = (power + 1) / 2; i < power; i++) {
inv_exp.push_back(h[i]);
}
inv_exp_fft = polynom_t<mint>(inv_exp).resize(power << 1);
fft(inv_exp_fft);
h.assign(power, 0);
std::copy(diff.begin(), diff.begin() + power - 1, h.begin());
fft(h);
for (int i = 0; i < power; i++) {
q[i] = exp_fft[i] * h[i];
}
inv_fft(q);
h.resize(power << 1);
for (int i = 1; i < power; i++) {
h[i] = exp[i] * i;
}
for (int i = 0; i < power; i++) {
h[i + 1] -= q[i];
}
h[0] = -q[power - 1];
fft(h);
q.resize(power << 1);
for (int i = 0; i < (power << 1); i++) {
q[i] = inv_exp_fft[i] * h[i];
}
inv_fft(q);
if (static_cast<int>(size()) >= power) {
h.assign(begin() + power, begin() + std::min<int>(power << 1, size()));
} else {
h.clear();
}
h.resize(power);
for (int i = power - 1; i >= 0; i--) {
h[i] -= q[i] * fft_data.inv(i + power);
}
h.resize(power << 1);
fft(h);
for (int i = 0; i < (power << 1); i++) {
q[i] = exp_fft[i] * h[i];
}
inv_fft(q);
exp.resize(power << 1);
for (int i = 0; i < power; i++) {
exp[power + i] = q[i];
}
}
return exp.resize(degree);
}
// Returns p^{d} modulo x^{degree}.
// O(n log).
polynom_t<mint> power(int64_t d, int degree) const {
if (!d || !degree) {
return polynom_t<mint>{1}.resize(degree);
}
int pos = 0;
while (pos < static_cast<int>(size()) && (*this)[pos] == mint(0)) {
pos++;
}
if (pos == static_cast<int>(size()) || pos >= (degree + d - 1) / d) {
return polynom_t<mint>(degree);
}
int coeffs_left = degree - d * pos;
polynom_t<mint> result = ((polynom_t<mint>(begin() + pos, end()) / (*this)[pos]).log(coeffs_left)
* mint(d)).exp(coeffs_left) * (*this)[pos].power(d);
result.resize(degree);
for (int i = degree - 1; i - (degree - coeffs_left) >= 0; i--) {
result[i] = result[i - (degree - coeffs_left)];
}
std::fill(result.begin(), result.end() - coeffs_left, mint(0));
return result;
}
// Returns f(x + c).
// O(n log).
polynom_t<mint> change_of_variable(mint c) const {
int n = size();
polynom_t<mint> p(n), q(n);
mint fact = 1, ifact = 1, power = 1;
for (int i = 0; i < n; i++) {
p[n - 1 - i] = (*this)[i] * fact;
q[i] = power * ifact;
fact *= i + 1;
ifact *= fft_data.inv(i + 1);
power *= c;
}
auto result = p * q;
result.resize(n);
std::reverse(result.begin(), result.end());
ifact = 1;
for (int i = 0; i < n; i++) {
result[i] *= ifact;
ifact *= fft_data.inv(i + 1);
}
return result;
}
template<typename V>
std::enable_if_t<!std::is_same_v<V, polynom_t<mint>>, polynom_t<mint>&> operator*=(const V &value) {
for (auto &x : *this) {
x *= value;
}
return *this;
}
template<typename V>
std::enable_if_t<!std::is_same_v<V, polynom_t<mint>>, polynom_t<mint>&> operator/=(const V &value) {
for (auto &x : *this) {
x /= value;
}
return *this;
}
friend std::ostream& operator<<(std::ostream &out, const polynom_t<mint> &p) {
for (int i = 0; i < static_cast<int>(p.size()); i++) {
if (i) out << ' ';
out << p[i];
}
return out;
}
friend polynom_t<mint> operator+(const polynom_t<mint> &p, const polynom_t<mint> &q) {
return polynom_t(p) += q;
}
friend polynom_t<mint> operator-(const polynom_t<mint> &p, const polynom_t<mint> &q) {
return polynom_t(p) -= q;
}
friend polynom_t<mint> operator*(const polynom_t<mint> &p, const polynom_t<mint> &q) {
return polynom_t(p) *= q;
}
friend polynom_t<mint> operator/(const polynom_t<mint> &p, const polynom_t<mint> &q) {
return polynom_t(p) /= q;
}
friend polynom_t<mint> operator%(const polynom_t<mint> &p, const polynom_t<mint> &q) {
return polynom_t(p) %= q;
}
template<typename V>
friend std::enable_if_t<!std::is_same_v<V, polynom_t<mint>>, polynom_t<mint>>
operator*(const V &value, const polynom_t<mint> &p) {
return polynom_t<mint>(p) *= value;
}
template<typename V>
friend std::enable_if_t<!std::is_same_v<V, polynom_t<mint>>, polynom_t<mint>>
operator*(const polynom_t<mint> &p, const V &value) {
return polynom_t<mint>(p) *= value;
}
template<typename V>
friend std::enable_if_t<!std::is_same_v<V, polynom_t<mint>>, polynom_t<mint>>
operator/(const V &value, const polynom_t<mint> &p) {
return polynom_t<mint>(p) /= value;
}
template<typename V>
friend std::enable_if_t<!std::is_same_v<V, polynom_t<mint>>, polynom_t<mint>>
operator/(const polynom_t<mint> &p, const V &value) {
return polynom_t<mint>(p) /= value;
}
};
using polynom = polynom_t<mint>;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, pos;
cin >> n >> pos;
pos--;
vector<mint> f(n);
{
// for (int l = 0; l < n; l++) {
// for (int r = 0; l + r < n; r++) {
// int rem_left = pos - l;
// int rem_right = n - 1 - pos - r;
// if (min(rem_left, rem_right) < 0) {
// continue;
// }
// auto lol = [&](int s, int k) {
// return catalan(s + k - 1, s);
// };
// mint ways = choose(l + r, l);
// ways *= lol(rem_left, l + 1) * lol(rem_right, r + 1);
// f[l + r] += ways;
// }
// }
polynom a(n);
for (int l = 0; l < n; l++) {
int rem = pos - l;
if (rem >= 0) {
a[l] = ifact[l] * catalan(rem + l, rem);
}
}
polynom b(n);
for (int r = 0; r < n; r++) {
int rem = n - 1 - pos - r;
if (rem >= 0) {
b[r] = ifact[r] * catalan(rem + r, rem);
}
}
auto c = a * b;
for (int i = 0; i < n; i++) {
f[i] = fact[i] * c[i];
}
}
vector<mint> g(n + 1);
{
// for (int subtree_size = 1; subtree_size <= n; subtree_size++) {
// int max_val = n - subtree_size;
// int vers = n - subtree_size + 1;
// for (int l = 0; l < subtree_size && l <= pos; l++) {
// int r = subtree_size - 1 - l;
// if (r > n - 1 - pos) {
// continue;
// }
// mint ways = catalan(l) * catalan(r);
// ways *= catalan(vers - 1);
// g[max_val + 1] += ways;
// }
// }
polynom a(n);
for (int l = 0; l <= pos; l++) {
a[l] = catalan(l);
}
polynom b(n);
for (int r = 0; r <= n - 1 - pos; r++) {
b[r] = catalan(r);
}
auto c = a * b;
for (int subtree_size = 1; subtree_size <= n; subtree_size++) {
int max_val = n - subtree_size;
int vers = n - subtree_size + 1;
g[max_val + 1] = c[subtree_size - 1] * catalan(vers - 1);
}
}
mint ans = 0;
for (int i = 0; i < n; i++) {
ans += f[i] - g[i];
cout << ans << '\n';
}
}
详细
Test #1:
score: 100
Accepted
time: 1ms
memory: 3536kb
input:
5 2
output:
5 10 16 20 14
result:
ok 5 number(s): "5 10 16 20 14"
Test #2:
score: 0
Accepted
time: 1ms
memory: 3756kb
input:
10 5
output:
588 1176 2716 4942 7407 9101 9636 9167 7596 4862
result:
ok 10 numbers
Test #3:
score: 0
Accepted
time: 183ms
memory: 32764kb
input:
500000 1
output:
752527092 752527092 356448531 118361535 80175537 877228690 209078427 453506156 121930551 870611121 548521681 932222500 877888556 339507693 727002572 260384266 821810888 163642149 575555577 658980933 234580785 344625334 385680534 342084167 446322884 625631289 815673835 143033406 834945846 697825903 4...
result:
ok 500000 numbers
Test #4:
score: 0
Accepted
time: 174ms
memory: 33068kb
input:
500000 233333
output:
138363804 276727608 913261867 200515458 98174965 678246093 927769485 382014114 279795571 189839383 793297320 457630387 247544984 428942831 277533813 88681322 624390630 921439292 168596569 954739113 979085346 687234058 393708687 497103558 286734849 179380498 473893314 393946995 822316346 485246191 92...
result:
ok 500000 numbers
Test #5:
score: 0
Accepted
time: 182ms
memory: 32752kb
input:
499999 114514
output:
341241717 682483434 394686579 953386037 677673958 904444378 480913543 895868144 176048066 234816259 736395238 354978365 6204402 236101366 864038383 804451311 473145556 770789285 76089413 836469366 829878019 448657883 22407787 956778740 776897403 375485911 804351816 370141803 717651675 394600139 5347...
result:
ok 499999 numbers
Test #6:
score: 0
Accepted
time: 173ms
memory: 31592kb
input:
466047 378542
output:
316308363 632616726 625328547 548058021 467831491 412249015 562771998 508534419 702318310 663161493 71297932 569391807 528363739 577103129 75851585 281129409 253324073 555237826 523497876 9329476 595651189 113409967 689415978 758768684 461344695 271342234 922636023 896745521 753799440 454281460 8498...
result:
ok 466047 numbers
Test #7:
score: 0
Accepted
time: 164ms
memory: 32768kb
input:
497799 442442
output:
540969780 83695207 921588610 541249578 212472530 147071951 843635401 456883686 551483676 319785278 129435321 398101925 294235139 653012857 781822424 891809319 10513719 612056872 376014502 828906445 950887259 230704126 807999128 290793371 246195343 411365869 934684624 509617751 998233677 996675668 34...
result:
ok 497799 numbers
Test #8:
score: 0
Accepted
time: 169ms
memory: 32092kb
input:
466753 419673
output:
597092992 195941631 35282209 670914306 416494384 664725208 464875750 709887141 730156891 961628244 14612612 245382798 764095090 474984466 17211503 243033312 636210322 917825652 374184874 65295028 974019379 560137128 569803312 547566684 460710417 911778842 953566231 318861526 622281663 898785393 3283...
result:
ok 466753 numbers
Test #9:
score: 0
Accepted
time: 161ms
memory: 29536kb
input:
467106 241969
output:
604311529 210378705 653856122 53407242 877563744 89862040 632233611 996021679 619177538 520557738 575283710 211917888 496972337 34709258 595060683 625661602 15046904 770633381 497290822 218631007 239931201 23236894 578432596 428901738 504948079 877566897 998082459 443758906 296654733 59363332 898295...
result:
ok 467106 numbers
Test #10:
score: 0
Accepted
time: 166ms
memory: 32360kb
input:
486061 115034
output:
331165032 662330064 25375445 506130213 871487194 485340585 595821481 719592290 466027466 441948467 508478606 8931379 859094189 505253385 804451132 52690798 925691683 108838807 681231074 644121957 911203033 190055176 696385690 936750672 753723350 200690758 840546153 39260738 242234801 958678150 92648...
result:
ok 486061 numbers
Test #11:
score: 0
Accepted
time: 160ms
memory: 31772kb
input:
467812 448354
output:
900296606 802348859 920449046 342092877 15903803 315457190 610050785 677368557 827898162 850348006 918145269 100413429 286141122 723506730 444503335 498737569 412741085 55182144 622915390 145398304 361786018 453817918 325379444 279159566 612579035 555703010 284796267 31457982 547199941 167269220 917...
result:
ok 467812 numbers
Test #12:
score: 0
Accepted
time: 166ms
memory: 32332kb
input:
486767 465253
output:
896140171 794035989 38457645 667018451 121077123 988018258 454886247 148667810 782822242 208886808 641186382 664983537 135609621 929099937 781283105 673597413 898333512 533372308 349436050 608656262 229842701 591579717 102946839 732166129 415428398 269284759 811402014 588459181 448836208 30635772 14...
result:
ok 486767 numbers
Test #13:
score: 0
Accepted
time: 163ms
memory: 28792kb
input:
455721 231993
output:
861554085 724863817 681201785 82707070 329170451 815432452 480078531 960748236 199985657 265729483 43600900 600505341 942806449 749230414 634217227 690651435 92408500 559745153 336853395 259055628 322977700 244145248 806934059 60422830 229138080 978023704 52573139 622964643 298105514 878856237 79116...
result:
ok 455721 numbers
Test #14:
score: 0
Accepted
time: 173ms
memory: 32412kb
input:
456074 166647
output:
550779515 103314677 680704969 104574508 421361420 116643622 662147096 817326397 947520551 180619995 27083749 470585529 491549290 514402213 308761194 350599064 923257834 308640880 614091608 114961735 934141925 413458402 982181885 925717354 288272850 10675839 578069676 657318380 431067097 927121546 45...
result:
ok 456074 numbers
Test #15:
score: 0
Accepted
time: 178ms
memory: 31764kb
input:
455455 165608
output:
818811474 639378595 559603642 505656460 732593061 518746340 763553035 619494907 724183639 517533699 565002043 469308457 942905250 972176896 126587792 234342559 715415951 639986417 796466894 23149560 432288560 256012618 37970347 784640990 338731371 397938827 514010733 565833174 65243657 565593692 685...
result:
ok 455455 numbers