結果

問題 No.3399 One Two Three Two Three
コンテスト
ユーザー akakimidori
提出日時 2025-03-12 20:37:42
言語 C++23
(gcc 13.3.0 + boost 1.89.0)
結果
AC  
実行時間 519 ms / 4,000 ms
コード長 5,391 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,462 ms
コンパイル使用メモリ 164,916 KB
実行使用メモリ 7,848 KB
最終ジャッジ日時 2025-12-05 23:31:38
合計ジャッジ時間 9,270 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 5
other AC * 40
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <cstdint>
#include <iostream>
#include <vector>
#include <initializer_list>

#include <atcoder/convolution>
#include <atcoder/modint>

using i64 = int64_t;
using i32 = int32_t;
using u32 = uint32_t;

using mint = atcoder::modint998244353;

template <class T>
T read() {
    T v;
    std::cin >> v;
    return v;
}

template <class T>
std::vector<T> vec(T elem, std::size_t len) {
    return std::vector<T>(len, elem);
}

class fps {
public:
    fps() = default;
    fps(const std::vector<mint> &x) : a(x) {}
    fps(const std::size_t len) : a(len, mint(0)) {}
    fps(const std::initializer_list<mint> init) : a(init.begin(), init.end()) {}
    static fps zero() { return fps(); }
    static fps one() { return fps{1}; }
    fps &operator+=(const fps &rhs) {
        if (a.size() < rhs.a.size()) {
            a.resize(rhs.a.size(), mint(0));
        }
        for (std::size_t i = 0; i < rhs.a.size(); ++i) a[i] += rhs.a[i];
        return *this;
    }
    fps &operator-=(const fps &rhs) {
        if (a.size() < rhs.a.size()) {
            a.resize(rhs.a.size(), mint(0));
        }
        for (std::size_t i = 0; i < rhs.a.size(); ++i) a[i] -= rhs.a[i];
        return *this;
    }
    fps &operator*=(const fps &rhs) {
        a = atcoder::convolution(a, rhs.a);
        return *this;
    }
    friend fps operator+(const fps &lhs, const fps &rhs) {
        return fps(lhs) += rhs;
    }
    friend fps operator-(const fps &lhs, const fps &rhs) {
        return fps(lhs) -= rhs;
    }
    friend fps operator*(const fps &lhs, const fps &rhs) {
        return fps(lhs) *= rhs;
    }
    const mint &operator[](const std::size_t x) const { return a.at(x); }
    mint &operator[](const std::size_t x) { return a.at(x); }
    std::size_t size() const { return a.size(); }
    void truncate(const std::size_t len) {
        if (len < a.size()) {
            a.resize(len);
        }
    }
    void resize(const std::size_t len) { a.resize(len, mint(0)); }
    fps step(const std::size_t s, const std::size_t k) const {
        assert(k > 0);
        std::vector<mint> res;
        for (std::size_t i = s; i < a.size(); i += k) res.emplace_back(a[i]);
        return res;
    }
    fps calc2() const {
        auto res = a;
        for (std::size_t i = 1; i < res.size(); i += 2) {
            res[i] = -res[i];
        }
        return res;
    }
    fps calc3() const {
        const std::size_t len = a.size();
        auto x = vec(fps(len), 2);
        auto y = vec(fps(len), 2);
        for (std::size_t i = 0; i < len; ++i) {
            const auto v = a[i];
            if (i % 3 == 0) {
                x[0][i] = y[0][i] = v;
            } else if (i % 3 == 1) {
                x[1][i] = v;
                y[0][i] = y[1][i] = -v;
            } else {
                y[1][i] = v;
                x[0][i] = x[1][i] = -v;
            }
        }
        return x[0] * y[0] - x[1] * y[1];
    }

private:
    std::vector<mint> a;
};

i64 ilog(i64 n, const i64 r) {
    assert(n >= 1 && r > 1);
    i64 c = 0;
    while (n >= r) {
        n /= r;
        c += 1;
    }
    return c;
}

int main() {
    const i64 n = read<i64>();
    const i64 h = ilog(n, 3);
    const i64 w = ilog(n, 2);
    const fps base{1, -1, -1, -1};
    const auto two = ([&] {
        auto two = vec(fps::one(), w + 1);
        for (std::size_t i = 1; i < two.size(); ++i) {
            const auto f = two[i - 1] * base;
            two[i] = (f * f.calc2()).step(0, 2);
        }
        return two;
    })();
    const auto three = ([&] {
        auto three = vec(fps::one(), h + 1);
        for (std::size_t i = 1; i < three.size(); ++i) {
            const auto f = three[i - 1] * base;
            three[i] = (f * f.calc3()).step(0, 3);
        }
        return three;
    })();
    auto calc_n = [&](std::size_t i, std::size_t j) -> i64 {
        i64 v = n;
        while (i--) v /= 3;
        while (j--) v /= 2;
        return v;
    };
    auto dp = vec(vec(std::pair<fps, fps>{}, w + 1), h + 1);
    mint ans = 0;
    for (std::size_t i = 0; i <= h; ++i) {
        fps bm_nu;
        for (std::size_t j = 0; j <= w; ++j) {
            fps nu, de;
            if (i > 0) {
                const auto [a, b] = std::exchange(dp[i - 1][j], {});
                const auto f = b.calc3();
                const auto r = calc_n(i - 1, j) % 3;
                nu = (a * f).step(r, 3) * two[j];
                de = (b * f).step(0, 3) * two[j];
            }
            if (j > 0) {
                const auto &[a, b] = dp[i][j - 1];
                const auto f = b.calc2();
                const auto r = calc_n(i, j - 1) % 2;
                bm_nu = (bm_nu * f).step(r, 2) * three[i];
                nu += (a * f).step(r, 2) * three[i];
                if (i == 0) de = (b * f).step(0, 2) * three[i];
            }
            if (i == 0 && j == 0) {
                nu = fps::one();
                de = fps::one();
            }
            bm_nu *= base;
            de *= base;
            bm_nu += nu * fps{0, 1};
            const auto m = calc_n(i, j);
            bm_nu.truncate(m + 1);
            nu.truncate(m + 1);
            de.truncate(m + 1);
            if (m == 1) {
                ans += bm_nu[0] * -de[1] + bm_nu[1];
                break;
            }
            dp[i][j] = std::make_pair(nu, de);
        }
    }
    std::cout << ans.val() << std::endl;
    return 0;
}
0