結果

問題 No.1302 Random Tree Score
コンテスト
ユーザー iastm
提出日時 2026-10-30 12:54:16
言語 C++23
(gcc 15.3.0 + boost 1.92.0 + ACL)
コンパイル:
g++-15 -O2 -fplugin=/usr/lib/yukicoder/noavx512-gcc15.so -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
AC  
実行時間 239 ms / 3,000 ms
+ 395µs
コード長 22,860 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 2,778 ms
コンパイル使用メモリ 231,276 KB
実行使用メモリ 11,028 KB
最終ジャッジ日時 2026-10-30 12:54:37
合計ジャッジ時間 6,539 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge7_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 13
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <iostream>
#include <vector>
#include <atcoder/modint>
// #include <kotone/formal_power_series>
// https://github.com/amiast/cpp-utility

#ifndef KOTONE_FORMAL_POWER_SERIES_HPP
#define KOTONE_FORMAL_POWER_SERIES_HPP 1

#include <vector>
#include <algorithm>
#include <cassert>
#include <atcoder/convolution>
// #include <kotone/internal_type_traits>
// https://github.com/amiast/cpp-utility

#ifndef KOTONE_INTERNAL_TYPE_TRAITS_HPP
#define KOTONE_INTERNAL_TYPE_TRAITS_HPP 1

#include <concepts>

namespace kotone {

template <typename T> concept number = std::is_arithmetic_v<T>;

template <typename T> concept signed_number = std::signed_integral<T> || std::floating_point<T>;

template <typename mint> concept compatible_modint = requires(mint a, mint b, int64_t x) {
    { mint::mod() } -> std::convertible_to<int>;
    mint{};
    mint{1};
    mint{x};

    { a + b }       -> std::same_as<mint>;
    { a - b }       -> std::same_as<mint>;
    { -a }          -> std::same_as<mint>;
    { a * b }       -> std::same_as<mint>;
    { a / b }       -> std::same_as<mint>;
    { a.inv() }     -> std::same_as<mint>;
    { a.pow(x) }    -> std::same_as<mint>;

    { a += b }      -> std::same_as<mint&>;
    { a -= b }      -> std::same_as<mint&>;
    { a *= b }      -> std::same_as<mint&>;
    { a /= b }      -> std::same_as<mint&>;

    { a == b }      -> std::convertible_to<bool>;
    { a != b }      -> std::convertible_to<bool>;
    { a.val() }     -> std::convertible_to<int>;
};

template <typename T> concept additive = requires(T a, T b) {
    T{};
    { a + b }       -> std::same_as<T>;
    { a - b }       -> std::same_as<T>;
    { -a }          -> std::same_as<T>;
    { a == b }      -> std::convertible_to<bool>;
    { a != b }      -> std::convertible_to<bool>;
};

template <typename T> concept mutable_additive = (
    additive<T>
    && requires(T a, T b) {
        { a += b }  -> std::same_as<T&>;
        { a -= b }  -> std::same_as<T&>;
        { ++a }     -> std::same_as<T&>;
        { --a }     -> std::same_as<T&>;
        { a++ }     -> std::same_as<T>;
        { a-- }     -> std::same_as<T>;
    }
);

}  // namespace kotone

#endif  // KOTONE_INTERNAL_TYPE_TRAITS

namespace kotone {

// A formal power series (`fps`) inherited from `vector<mint>` that supports various operations.
template <compatible_modint mint, bool using_ntt = true> struct formal_power_series : std::vector<mint> {
    using fps = formal_power_series;
    using std::vector<mint>::vector;
    using std::vector<mint>::operator=;

    // Adds `other` to `*this`.
    fps& operator+=(const fps &other) {
        if (this->size() < other.size()) this->resize(other.size());
        for (std::size_t i = 0; i < other.size(); i++) (*this)[i] += other[i];
        return *this;
    }

    // Subtracts `other` from `*this`.
    fps& operator-=(const fps &other) {
        if (this->size() < other.size()) this->resize(other.size());
        for (std::size_t i = 0; i < other.size(); i++) (*this)[i] -= other[i];
        return *this;
    }

    // Multiplies `*this` by `other`.
    fps& operator*=(const fps &other) {
        if (this->empty() || other.empty()) this->clear();
        else if constexpr (using_ntt) *this = atcoder::convolution(*this, other);
        else {
            fps result(this->size() + other.size() - 1);
            for (std::size_t i = 0; i < this->size(); i++) {
                for (std::size_t j = 0; j < other.size(); j++) {
                    result[i + j] += (*this)[i] * other[j];
                }
            }
            *this = result;
        }
        return *this;
    }

    // Multiplies each coefficient by `m`.
    fps& operator*=(const mint &m) { for (mint &c : *this) c *= m; return *this; }
    // Divides each coefficient by `m`.
    // Requires `m != 0`.
    fps& operator/=(const mint &m) { assert(m != 0); for (mint &c : *this) c /= m; return *this; }

    // Returns a copy of `*this`.
    fps operator+() const { return *this; }
    // Returns a copy of negated `*this`.
    fps operator-() const { return fps{} - *this; }

    // Returns `*this` evaluated at `m`.
    mint operator()(const mint &m) const {
        mint result = 0;
        for (std::size_t i = this->size(); i--;) {
            result *= m;
            result += (*this)[i];
        }
        return result;
    }

    // Strips trailing `0`'s.
    void strip() { while (this->size() && this->back() == 0) this->pop_back(); }

    // Divides `*this` by `other` and assigns the quotient to `*this`.
    // Requires `other` to contain nonzero coefficients.
    fps& operator/=(const fps &other) {
        fps denom(other.begin(), other.end());
        denom.strip();
        assert(!denom.empty());
        fps num(this->begin(), this->end());
        num.strip();
        int n = num.size(), m = denom.size();
        if (n < m) {
            this->clear();
            return *this;
        }
        std::reverse(denom.begin(), denom.end());
        std::reverse(num.begin(), num.end());
        *this = num * inverse(denom, n - m + 1);
        this->resize(n - m + 1);
        std::reverse(this->begin(), this->end());
        return *this;
    }

    // Divides `*this` by `other` and assigns the remainder to `*this`.
    // Requires `other` to contain nonzero coefficients.
    fps& operator%=(const fps &other) {
        fps denom(other.begin(), other.end());
        denom.strip();
        assert(!denom.empty());
        fps num(this->begin(), this->end());
        num.strip();
        int n = num.size(), m = denom.size();
        if (n < m) return *this;
        std::reverse(denom.begin(), denom.end());
        std::reverse(num.begin(), num.end());
        fps quo = num * inverse(denom, n - m + 1);
        quo.resize(n - m + 1);
        std::reverse(quo.begin(), quo.end());
        *this -= quo * other;
        this->resize(m - 1);
        return *this;
    }

    // Returns a `vector` containing the results of evaluating `*this` at each point in `vec`.
    std::vector<mint> eval(const std::vector<mint> &vec) {
        int m = vec.size(), len = 1;
        while (len < m) len *= 2;
        std::vector<fps> nodes(len * 2);
        for (int i = 0; i < m; i++) nodes[len + i] = {-vec[i], 1};
        for (int i = m; i < len; i++) nodes[len + i] = {1};
        for (int i = len - 1; i > 0; i--) nodes[i] = nodes[i * 2] * nodes[i * 2 + 1];
        std::vector<mint> result(m);
        auto solve = [&](auto &solve, int i, fps poly) {
            if (i >= len + m) return;
            poly %= nodes[i];
            if (i >= len) {
                result[i - len] = poly[0];
                return;
            }
            solve(solve, i * 2, poly);
            solve(solve, i * 2 + 1, poly);
        };
        solve(solve, 1, *this);
        return result;
    }

    // Returns the sum of `a` and `b`.
    friend fps operator+(const fps &a, const fps &b) { fps c = a; return c += b; }
    // Returns the difference of `a` and `b`.
    friend fps operator-(const fps &a, const fps &b) { fps c = a; return c -= b; }
    // Returns the product of `a` and `b`.
    friend fps operator*(const fps &a, const fps &b) { fps c = a; return c *= b; }
    // Returns `a` with its coefficients multiplied by `b`.
    friend fps operator*(const fps &a, const mint &b) { fps c = a; return c *= b; }
    // Returns `b` with its coefficients multiplied by `a`.
    friend fps operator*(const mint &a, const fps &b) { return b * a; }
    // Returns `a` with its coefficients divided by `b`.
    // Requires `b != 0`.
    friend fps operator/(const fps &a, const mint &b) { assert(b != 0); fps c = a; return c /= b; }
    // Returns the quotient of `a` and `b`.
    // Requires `b` to contain nonzero coefficients.
    friend fps operator/(const fps &a, const fps &b) { fps c = a; return c /= b; }
    // Returns the remainder of `a` and `b`.
    // Requires `b` to contain nonzero coefficients.
    friend fps operator%(const fps &a, const fps &b) { fps c = a; return c %= b; }

    // Returns the inverse of `f` up to the first `n` coefficients.
    // Requires `!f.empty()`.
    // Requires `f[0] != 0`.
    // Requires `n >= 0`.
    static fps inverse(const fps &f, int n) {
        assert(!f.empty());
        assert(f[0] != 0);
        assert(n >= 0);
        if (n == 0) return {};
        fps result{f[0].inv()};
        int m = 1;
        int len = f.size();
        while (m < n) {
            m = std::min(m * 2, n);
            fps sub(f.begin(), f.begin() + std::min(m, len));
            if (m > len) sub.resize(m);
            fps prod = result * sub;
            prod.resize(m);
            prod[0] = 2 - prod[0];
            for (int i = 1; i < m; i++) prod[i] = -prod[i];
            result *= prod;
            result.resize(m);
        }
        result.resize(n);
        return result;
    }

    // Returns a `pair` containing the quotient and remainder of `f` and `g`.
    // Requires `g` to contain nonzero coefficients.
    static std::pair<fps, fps> divmod(const fps &f, const fps &g) {
        fps denom(g.begin(), g.end());
        denom.strip();
        assert(!denom.empty());
        fps num(f.begin(), f.end());
        num.strip();
        int n = num.size(), m = denom.size();
        if (n < m) return {{}, f};
        std::reverse(denom.begin(), denom.end());
        std::reverse(num.begin(), num.end());
        fps quo = num * inverse(denom, n - m + 1);
        quo.resize(n - m + 1);
        std::reverse(quo.begin(), quo.end());
        std::reverse(num.begin(), num.end());
        num -= quo * g;
        num.resize(m - 1);
        return {quo, num};
    }

    // Returns the derivative of `f`.
    // Returns an empty vector if `f` is empty.
    static fps derivative(const fps &f) {
        if (f.empty()) return {};
        fps result(f.begin() + 1, f.end());
        for (std::size_t i = 0; i < result.size(); i++) result[i] *= i + 1;
        return result;
    }

    // Returns the integral of `f`.
    // Sets the `0`-th coefficent of the integral as `0`.
    // If `f` is empty, returns an empty vector.
    static fps integral(const fps &f) {
        if (f.empty()) return {};
        int len = f.size();
        fps result(len + 1);
        result[1] = 1;
        for (int i = 2, p = mint::mod(); i <= len; i++) {
            result[i] = p / i * -result[p % i];
        }
        for (int i = 0; i < len; i++) result[i + 1] *= f[i];
        return result;
    }

    // Returns the logarithm of `f` up to the first `n` coefficients.
    // Requires `!f.empty()`.
    // Requires `f[0] == 1`.
    // Requires `n >= 0`.
    static fps logarithm(const fps &f, int n) {
        assert(!f.empty());
        assert(f[0] == 1);
        assert(n >= 0);
        if (n == 0) return {};
        fps prod;
        if (int len = f.size(); len <= n) prod = derivative(f);
        else prod = derivative({f.begin(), f.begin() + n});
        prod *= inverse(f, n - 1);
        prod.resize(n - 1);
        fps result = integral(prod);
        result.resize(n);
        return result;
    }

    // Returns the exponential of `f` up to the first `n` coefficients.
    // Requires `f.empty() || f[0] == 0`.
    // Requires `n >= 0`.
    static fps exponential(const fps &f, int n) {
        assert(f.empty() || f[0] == 0);
        assert(n >= 0);
        if (n == 0) return {};
        fps result{1};
        if (f.empty()) {
            result.resize(n);
            return result;
        }
        int m = 1;
        int len = f.size();
        while (m < n) {
            m = std::min(m * 2, n);
            fps log = -logarithm(result, m);
            for (int i = 0; i < m && i < len; i++) log[i] += f[i];
            log[0]++;
            result *= log;
            result.resize(m);
        }
        return result;
    }

    // Returns `f` raised to the specified `pow` up to the first `n` coefficients.
    // If `pow == 0`, the resulting `fps` is equivalent to `1`.
    // If `pow > 0 && f.empty()`, the resulting `fps` is equivalent to `0`.
    // Requires `pow >= 0`.
    // Requires `n >= 0`.
    static fps power(const fps &f, int64_t pow, int n) {
        assert(pow >= 0);
        assert(n >= 0);
        if (n == 0) return {};
        if (pow == 0) {
            fps result(n);
            result[0] = 1;
            return result;
        }
        int d = -1;
        {
            int64_t len = f.size();
            int64_t q = (n + pow - 1) / pow;
            if (q > len) q = len;
            for (int i = 0; i < q; i++) {
                if (f[i] == 0) continue;
                d = i;
                break;
            }
            if (d == -1) return fps(n);
        }
        int shift = d * pow;
        int len = f.size() - d;
        if (len > n - shift) len = n - shift;
        fps g(f.begin() + d, f.begin() + d + len);
        mint acc = g[0].pow(pow);
        g = logarithm(g / g[0], n - shift) * pow;
        g = exponential(g, n - shift) * acc;
        fps result(n);
        for (int i = 0; i + shift < n; i++) result[i + shift] = g[i];
        return result;
    }

    // Computes the coefficient of the term with the specified degree `k` in the rational function.
    // Requires `!denominator.empty() && denominator[0] != 0`.
    // Requires `k >= 0`.
    // Reference: https://info.atcoder.jp/entry/algorithm_lectures/linearly_recurrent_sequence_kth_term
    static mint bostan_mori(fps numerator, fps denominator, int64_t k) {
        assert(!denominator.empty() && denominator[0] != 0);
        assert(k >= 0);
        if (numerator.empty()) return 0;
        while (k) {
            fps denom_neg = denominator;
            for (std::size_t i = 1; i < denom_neg.size(); i += 2) {
                denom_neg[i] = -denom_neg[i];
            }
            numerator *= denom_neg;
            denominator *= denom_neg;
            fps new_num, new_denom;
            new_num.reserve((numerator.size() + 1) >> 1);
            new_denom.reserve((denominator.size() + 1) >> 1);
            for (std::size_t i = k & 1; i < numerator.size(); i += 2) new_num.push_back(numerator[i]);
            for (std::size_t i = 0; i < denominator.size(); i += 2) new_denom.push_back(denominator[i]);
            numerator = new_num;
            denominator = new_denom;
            k >>= 1;
        }
        return numerator[0] / denominator[0];
    }

    // Computes term `a[k]` of a homogeneous linear recurrence `a` of order `n`.
    // More specifically, `recurrence` specifies coefficients `c` in the relation
    // `a[i] = c[0] * a[i - 1] + ... + c[n - 1] * a[i - n]`.
    // Returns `0` if `recurrence` and `init` are empty.
    // Requires `recurrence.size() == init.size()`.
    // Requires `k >= 0`.
    static mint solve_recurrence(const fps &recurrence, const fps &init, int64_t k) {
        assert(recurrence.size() == init.size());
        assert(k >= 0);
        int n = recurrence.size();
        if (n == 0) return 0;
        if (k < n) return init[k];
        fps denominator(n + 1, 1);
        for (int i = 0; i < n; i++) denominator[i + 1] = -recurrence[i];
        fps numerator = denominator * init;
        numerator.resize(n);
        return bostan_mori(numerator, denominator, k);
    }

    // Given a vector of pairs `{x_i, y_i}`, returns `f` such that `f(x_i) == y_i` for all `i`.
    // Requires `vec` to contain distinct `x_i`'s.
    static fps interpolate(const std::vector<std::pair<mint, mint>> &vec) {
        int m = vec.size(), len = 1;
        while (len < m) len *= 2;
        std::vector<fps> nodes(len * 2);
        for (int i = 0; i < m; i++) nodes[i + len] = {-vec[i].first, 1};
        for (int i = m; i < len; i++) nodes[i + len] = {1};
        for (int i = len - 1; i > 0; i--) nodes[i] = nodes[i * 2] * nodes[i * 2 + 1];
        auto solve = [&](auto &solve, int i, fps poly) -> fps {
            if (i >= len + m) return {};
            poly %= nodes[i];
            if (i >= len) {
                assert(poly[0] != 0);
                return {vec[i - len].second / poly[0]};
            }
            return solve(solve, i * 2, poly) * nodes[i * 2 + 1] + solve(solve, i * 2 + 1, poly) * nodes[i * 2];
        };
        return solve(solve, 1, fps::derivative(nodes[1]));
    }

    // Given `f(x)`, returns `f(y)` where `y == x + offset`.
    static fps taylor_shift(const fps &f, mint offset) {
        int len = f.size();
        fps result(len, 1), p(len), q(len);
        for (int i = 2, p = mint::mod(); i < len; i++) {
            result[i] = p / i * -result[p % i];
        }
        for (int i = 1; i < len; i++) result[i] *= result[i - 1];
        mint acc = 1;
        for (int i = 0; i < len; i++) {
            p[len - 1 - i] = f[i] * acc;
            acc *= i + 1;
        }
        acc = 1;
        for (int i = 0; i < len; i++) {
            q[i] = result[i] * acc;
            acc *= offset;
        }
        fps r = p * q;
        for (int i = 0; i < len; i++) result[i] *= r[len - 1 - i];
        return result;
    }
};

}  // namespace kotone

#endif  // KOTONE_FORMAL_POWER_SERIES_HPP
// #include <kotone/modint_utility>
// https://github.com/amiast/cpp-utility

#ifndef KOTONE_MODINT_UTILITY_HPP
#define KOTONE_MODINT_UTILITY_HPP 1

#include <vector>
#include <cassert>
// #include <kotone/internal_type_traits>
// https://github.com/amiast/cpp-utility


namespace kotone {

// Returns a length-`(n+1)` vector `reciprocal` such that `reciprocal[i]` is the modular inverse of `i`.
// The value of `reciprocal[0]` is undefined.
// Requires `mint::mod()` to be prime.
// Requires `1 <= n < mint::mod()`.
template <compatible_modint mint> std::vector<mint> reciprocals(int n) {
    int p = mint::mod();
    assert(1 <= n && n <= p);
    std::vector<mint> result(n + 1);
    result[1] = 1;
    for (int i = 2; i <= n; i++) {
        result[i] = -(p / i) * result[p % i];
    }
    return result;
}

// Returns a vector containing the first `n + 1` factorials (`0!, 1!, ..., n!`).
// Requires `n >= 0`.
template <compatible_modint mint> std::vector<mint> factorials(int n) {
    assert(n >= 0);
    std::vector<mint> result(n + 1);
    result[0] = 1;
    for (int i = 1; i <= n; i++) result[i] = i * result[i - 1];
    return result;
}

// Returns a vector of inverse factorials given the vector of factorials.
// Requires `vec_factorial` to match the format of the output of `factorials()`.
// Requires `mint::mod()` to be prime.
// Requires `1 <= vec_factorial.size() <= mint::mod()`.
template <compatible_modint mint> std::vector<mint> inv_factorials(const std::vector<mint> &vec_factorial) {
    int len = vec_factorial.size();
    int p = mint::mod();
    assert(1 <= len && len <= p);
    std::vector<mint> result(len);
    assert(vec_factorial[len - 1] != 0);
    result[len - 1] = vec_factorial[len - 1].inv();
    for (int i = len - 1; i > 0; i--) result[i - 1] = i * result[i];
    return result;
}

// A wrapper class for combinatorial functions with modint.
template <compatible_modint mint> struct modint_utility {
  private:
    std::vector<mint> _inv, _fact, _ifact;
    int _p = -1, _max_n = -1;

    void _build(int new_max) {
        if (new_max <= _max_n) return;
        _inv.resize(new_max + 1, 1);
        _fact.resize(new_max + 1, 1);
        _ifact.resize(new_max + 1, 1);
        for (int i = std::max(_max_n + 1, 2); i <= new_max; i++) {
            _inv[i] = -(_p / i) * _inv[_p % i];
        }
        for (int i = std::max(_max_n + 1, 2); i <= new_max; i++) _fact[i] = i * _fact[i - 1];
        for (int i = std::max(_max_n + 1, 2); i <= new_max; i++) _ifact[i] = _inv[i] * _ifact[i - 1];
        _max_n = new_max;
    }

  public:
    modint_utility() : _p(mint::mod()) {}

    // Instantiates with the first `n + 1` factorials (`0!, 1!, ..., n!`) precomputed.
    // Requires `mint::mod()` to be prime.
    // Requires `mint::mod()` to be invariant.
    // Requires `n < mint::mod()`.
    modint_utility(int n) {
        _p = mint::mod();
        assert(n < _p);
        _build(n);
    }

    // Returns the modular inverse of `n`.
    // Requires `1 <= n < mint::mod()`.
    mint inv(int n) {
        assert(1 <= n && n < _p);
        if (n >= _max_n) _build(n);
        return _inv[n];
    }

    // Returns `n!`.
    // Requires `0 <= n < mint::mod()`.
    mint factorial(int n) {
        assert(0 <= n && n < _p);
        if (n >= _max_n) _build(n);
        return _fact[n];
    }

    // Returns the modular inverse of `n!`.
    // Requires `0 <= n < mint::mod()`.
    mint inv_factorial(int n) {
        assert(0 <= n && n < _p);
        if (n >= _max_n) _build(n);
        return _ifact[n];
    }

    // Returns the number of permutations of `k` of `n` objects.
    // Requires `0 <= k <= n < mint::mod()`.
    mint perm(int n, int k) {
        assert(0 <= k && k <= n && n < _p);
        if (n >= _max_n) _build(n);
        return _fact[n] * _ifact[n - k];
    }

    // Returns the number of combinations of `k` of `n` objects.
    // Requires `0 <= k <= n < mint::mod()`.
    mint comb(int n, int k) {
        assert(0 <= k && k <= n && n < _p);
        if (n >= _max_n) _build(n);
        return _fact[n] * _ifact[k] * _ifact[n - k];
    }

    // Returns the `n`-th Catalan number.
    // Requires `0 <= n * 2 < _p`.
    mint catalan(int n) {
        assert(0 <= n && n * 2 < _p);
        if (n * 2 >= _max_n) _build(n * 2);
        return _fact[n * 2] * _ifact[n + 1] * _ifact[n];
    }
};

// Returns a square root of the given value.
// If no square root exists, returns `0`.
// If there are multiple square roots, the function may return any of them.
template <compatible_modint mint> mint sqrt_mint(mint val) {
    if (val == 0) return 0;
    int mod = mint::mod();
    if (mod == 2) return val;
    if (val.pow((mod - 1) / 2) == -1) return 0;
    if (mod % 4 == 3) return val.pow((mod + 1) / 4);

    int s = 0;
    int q = mod - 1;
    while (q % 2 == 0) {
        q /= 2;
        s++;
    }

    mint z = 2;
    while (z.pow((mod - 1) / 2) == 1) z++;
    mint c = z.pow(q);
    mint x = val.pow((q + 1) / 2);
    mint t = val.pow(q);

    while (t != 1) {
        int i = 0;
        mint tpow = t;
        while (tpow != 1 && i < s) {
            tpow *= tpow;
            i++;
        }
        if (i == s) return 0;
        mint b = c.pow(1 << (s - i - 1));
        x *= b;
        t *= b * b;
        c = b * b;
        s = i;
    }
    return x;
}

}  // namespace kotone

#endif  // KOTONE_MODINT_UTILITY_HPP

using mint = atcoder::modint998244353;
using fps = kotone::formal_power_series<mint>;

int main() {
    int N;
    std::cin >> N;
    kotone::modint_utility<mint> util(N);
    fps f(N);
    for (int i = 0; i < N; i++) f[i] = util.inv_factorial(i) * (i + 1);
    mint result = fps::power(f, N, N - 1)[N - 2];
    result *= util.factorial(N - 2);
    result /= mint(N).pow(N - 2);
    std::cout << result.val() << std::endl;
}
0