結果
問題 |
No.3172 三角関数べき乗のフーリエ級数展開
|
ユーザー |
|
提出日時 | 2025-06-06 21:44:51 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 113 ms / 2,000 ms |
コード長 | 51,259 bytes |
コンパイル時間 | 2,105 ms |
コンパイル使用メモリ | 152,292 KB |
実行使用メモリ | 9,496 KB |
最終ジャッジ日時 | 2025-06-06 21:44:56 |
合計ジャッジ時間 | 3,769 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 15 |
ソースコード
#include <deque> #include <stack> #include <functional> #include <istream> #include <queue> #include <unordered_map> #include <list> #include <utility> #include <iomanip> #include <numeric> #include <iterator> #include <string> #include <fstream> #include <ostream> #include <iostream> #include <type_traits> #include <set> #include <array> #include <unordered_set> #include <vector> #include <map> #include <optional> #include <algorithm> #include <bitset> #include <cassert> #ifndef KK2_TEMPLATE_PROCON_HPP #define KK2_TEMPLATE_PROCON_HPP 1 #ifndef KK2_TEMPLATE_CONSTANT_HPP #define KK2_TEMPLATE_CONSTANT_HPP 1 #ifndef KK2_TEMPLATE_TYPE_ALIAS_HPP #define KK2_TEMPLATE_TYPE_ALIAS_HPP 1 using u32 = unsigned int; using i64 = long long; using u64 = unsigned long long; using i128 = __int128_t; using u128 = __uint128_t; using pi = std::pair<int, int>; using pl = std::pair<i64, i64>; using pil = std::pair<int, i64>; using pli = std::pair<i64, int>; template <class T> using vc = std::vector<T>; template <class T> using vvc = std::vector<vc<T>>; template <class T> using vvvc = std::vector<vvc<T>>; template <class T> using vvvvc = std::vector<vvvc<T>>; template <class T> using pq = std::priority_queue<T>; template <class T> using pqi = std::priority_queue<T, std::vector<T>, std::greater<T>>; #endif // KK2_TEMPLATE_TYPE_ALIAS_HPP template <class T> constexpr T infty = 0; template <> constexpr int infty<int> = (1 << 30) - 123; template <> constexpr i64 infty<i64> = (1ll << 62) - (1ll << 31); template <> constexpr i128 infty<i128> = (i128(1) << 126) - (i128(1) << 63); template <> constexpr u32 infty<u32> = infty<int>; template <> constexpr u64 infty<u64> = infty<i64>; template <> constexpr u128 infty<u128> = infty<i128>; template <> constexpr double infty<double> = infty<i64>; template <> constexpr long double infty<long double> = infty<i64>; constexpr int mod = 998244353; constexpr int modu = 1e9 + 7; constexpr long double PI = 3.14159265358979323846; #endif // KK2_TEMPLATE_CONSTANT_HPP #ifndef KK2_TEMPLATE_FUNCTION_UTIL_HPP #define KK2_TEMPLATE_FUNCTION_UTIL_HPP 1 #ifndef KK2_MATH_MONOID_MAX_HPP #define KK2_MATH_MONOID_MAX_HPP 1 #ifndef KK2_TYPE_TRAITS_IO_HPP #define KK2_TYPE_TRAITS_IO_HPP 1 namespace kk2 { namespace type_traits { struct istream_tag {}; struct ostream_tag {}; } // namespace type_traits template <typename T> using is_standard_istream = typename std::conditional<std::is_same<T, std::istream>::value || std::is_same<T, std::ifstream>::value, std::true_type, std::false_type>::type; template <typename T> using is_standard_ostream = typename std::conditional<std::is_same<T, std::ostream>::value || std::is_same<T, std::ofstream>::value, std::true_type, std::false_type>::type; template <typename T> using is_user_defined_istream = std::is_base_of<type_traits::istream_tag, T>; template <typename T> using is_user_defined_ostream = std::is_base_of<type_traits::ostream_tag, T>; template <typename T> using is_istream = typename std::conditional<is_standard_istream<T>::value || is_user_defined_istream<T>::value, std::true_type, std::false_type>::type; template <typename T> using is_ostream = typename std::conditional<is_standard_ostream<T>::value || is_user_defined_ostream<T>::value, std::true_type, std::false_type>::type; template <typename T> using is_istream_t = std::enable_if_t<is_istream<T>::value>; template <typename T> using is_ostream_t = std::enable_if_t<is_ostream<T>::value>; } // namespace kk2 #endif // KK2_TYPE_TRAITS_IO_HPP namespace kk2 { namespace monoid { template <class S, class Compare = std::less<S>> struct Max { static constexpr bool commutative = true; using M = Max; S a; bool is_unit; Max() : a(S()), is_unit(true) {} Max(S a_) : a(a_), is_unit(false) {} operator S() const { return a; } inline static M op(M l, M r) { if (l.is_unit or r.is_unit) return l.is_unit ? r : l; return Compare{}(l.a, r.a) ? r : l; } inline static M unit() { return M(); } bool operator==(const M &rhs) const { return is_unit == rhs.is_unit and (is_unit or a == rhs.a); } bool operator!=(const M &rhs) const { return is_unit != rhs.is_unit or (!is_unit and a != rhs.a); } template <class OStream, is_ostream_t<OStream> * = nullptr> friend OStream &operator<<(OStream &os, const M &x) { if (x.is_unit) os << "-inf"; else os << x.a; return os; } template <class IStream, is_istream_t<IStream> * = nullptr> friend IStream &operator>>(IStream &is, M &x) { is >> x.a; x.is_unit = false; return is; } }; } // namespace monoid } // namespace kk2 #endif // MATH_MONOID_MAX_HPP #ifndef KK2_MATH_MONOID_MIN_HPP #define KK2_MATH_MONOID_MIN_HPP 1 namespace kk2 { namespace monoid { template <class S, class Compare = std::less<S>> struct Min { static constexpr bool commutative = true; using M = Min; S a; bool is_unit; Min() : a(S()), is_unit(true) {} Min(S a_) : a(a_), is_unit(false) {} operator S() const { return a; } inline static M op(M l, M r) { if (l.is_unit or r.is_unit) return l.is_unit ? r : l; return Compare{}(l.a, r.a) ? l : r; } inline static M unit() { return M(); } bool operator==(const M &rhs) const { return is_unit == rhs.is_unit and (is_unit or a == rhs.a); } bool operator!=(const M &rhs) const { return is_unit != rhs.is_unit or (!is_unit and a != rhs.a); } template <class OStream, is_ostream_t<OStream> * = nullptr> friend OStream &operator<<(OStream &os, const M &x) { if (x.is_unit) os << "inf"; else os << x.a; return os; } template <class IStream, is_istream_t<IStream> * = nullptr> friend IStream &operator>>(IStream &is, M &x) { is >> x.a; x.is_unit = false; return is; } }; } // namespace monoid } // namespace kk2 #endif // KK2_MATH_MONOID_MIN_HPP #ifndef KK2_TYPE_TRAITS_CONTAINER_TRAITS_HPP #define KK2_TYPE_TRAITS_CONTAINER_TRAITS_HPP 1 namespace kk2 { template <typename T> struct is_vector : std::false_type {}; template <typename T, typename Alloc> struct is_vector<std::vector<T, Alloc>> : std::true_type {}; // コンテナかどうかを判定するtraits template <typename T> struct is_container : std::false_type {}; // 基本的なコンテナ型の特殊化 template <typename T, typename Alloc> struct is_container<std::vector<T, Alloc>> : std::true_type { }; template <typename CharT, typename Traits, typename Alloc> struct is_container<std::basic_string<CharT, Traits, Alloc>> : std::true_type {}; template <typename T, std::size_t N> struct is_container<std::array<T, N>> : std::true_type {}; template <typename T, typename Alloc> struct is_container<std::deque<T, Alloc>> : std::true_type {}; template <typename T, typename Alloc> struct is_container<std::list<T, Alloc>> : std::true_type {}; // SFINAEでコンテナを判定するためのヘルパー template <typename T> using is_container_t = typename std::enable_if_t<is_container<T>::value, std::nullptr_t>; } // namespace kk2 #endif // KK2_TYPE_TRAITS_CONTAINER_TRAITS_HPP namespace kk2 { template <class T, class... Sizes> auto make_vector(int first, Sizes... sizes) { if constexpr (sizeof...(sizes) == 0) { return std::vector<T>(first); } else { return std::vector<decltype(make_vector<T>(sizes...))>(first, make_vector<T>(sizes...)); } } template <class T, class U> void fill_all(std::vector<T> &v, const U &x) { if constexpr (is_vector<T>::value) { for (auto &u : v) fill_all(u, x); } else { std::fill(v.begin(), v.end(), T(x)); } } template <class T, class U> int iota_all(std::vector<T> &v, U x, int offset = 0) { if constexpr (is_vector<T>::value) { for (auto &u : v) offset += iota_all(u, x + offset); } else { for (auto &u : v) u = x++, ++offset; } return offset; } template <class C> int mysize(const C &c) { return size(c); } // T: commutative monoid, F: (U, T) -> U template <class U, class T, class F> U all_monoid_prod(const std::vector<T> &v, U unit, const F &f) { U res = unit; if constexpr (is_vector<T>::value) { for (const auto &x : v) res = f(res, all_monoid_prod(x, unit, f)); } else { for (const auto &x : v) res = f(res, x); } return res; } template <class U, class T> U all_sum(const std::vector<T> &v, U unit = U()) { return all_monoid_prod<U, T>(v, unit, [](U a, U b) { return a + b; }); } template <class U, class T> U all_prod(const std::vector<T> &v, U unit = U(1)) { return all_monoid_prod<U, T>(v, unit, [](U a, U b) { return a * b; }); } template <class U, class T> U all_xor(const std::vector<T> &v, U unit = U()) { return all_monoid_prod<U, T>(v, unit, [](U a, U b) { return a ^ b; }); } template <class U, class T> U all_and(const std::vector<T> &v, U unit = U(-1)) { return all_monoid_prod<U, T>(v, unit, [](U a, U b) { return a & b; }); } template <class U, class T> U all_or(const std::vector<T> &v, U unit = U()) { return all_monoid_prod<U, T>(v, unit, [](U a, U b) { return a | b; }); } template <class U, class T> U all_min(const std::vector<T> &v) { return all_monoid_prod<monoid::Min<U>, T>(v, monoid::Min<U>::unit(), monoid::Min<U>::op); } template <class U, class T> U all_max(const std::vector<T> &v) { return all_monoid_prod<monoid::Max<U>, T>(v, monoid::Max<U>::unit(), monoid::Max<U>::op); } template <class U, class T> U all_gcd(const std::vector<T> &v, U unit = U()) { return all_monoid_prod<U, T>(v, unit, [](U a, U b) { return std::gcd(a, b); }); } template <class U, class T> U all_lcm(const std::vector<T> &v, U unit = U(1)) { return all_monoid_prod<U, T>(v, unit, [](U a, U b) { return std::lcm(a, b); }); } } // namespace kk2 #endif // KK2_TEMPLATE_FUNCTION_UTIL_HPP #ifndef KK2_TEMPLATE_IO_UTIL_HPP #define KK2_TEMPLATE_IO_UTIL_HPP 1 // なんかoj verifyはプロトタイプ宣言が落ちる namespace impl { struct read { template <class IStream, class T> inline static void all_read(IStream &is, T &x) { is >> x; } template <class IStream, class T, class U> inline static void all_read(IStream &is, std::pair<T, U> &p) { all_read(is, p.first); all_read(is, p.second); } template <class IStream, class T> inline static void all_read(IStream &is, std::vector<T> &v) { for (T &x : v) all_read(is, x); } template <class IStream, class T, size_t F> inline static void all_read(IStream &is, std::array<T, F> &a) { for (T &x : a) all_read(is, x); } }; struct write { template <class OStream, class T> inline static void all_write(OStream &os, const T &x) { os << x; } template <class OStream, class T, class U> inline static void all_write(OStream &os, const std::pair<T, U> &p) { all_write(os, p.first); all_write(os, ' '); all_write(os, p.second); } template <class OStream, class T> inline static void all_write(OStream &os, const std::vector<T> &v) { for (int i = 0; i < (int)v.size(); ++i) { if (i) all_write(os, ' '); all_write(os, v[i]); } } template <class OStream, class T, size_t F> inline static void all_write(OStream &os, const std::array<T, F> &a) { for (int i = 0; i < (int)F; ++i) { if (i) all_write(os, ' '); all_write(os, a[i]); } } }; } // namespace impl template <class IStream, class T, class U, kk2::is_istream_t<IStream> * = nullptr> IStream &operator>>(IStream &is, std::pair<T, U> &p) { impl::read::all_read(is, p); return is; } template <class IStream, class T, kk2::is_istream_t<IStream> * = nullptr> IStream &operator>>(IStream &is, std::vector<T> &v) { impl::read::all_read(is, v); return is; } template <class IStream, class T, size_t F, kk2::is_istream_t<IStream> * = nullptr> IStream &operator>>(IStream &is, std::array<T, F> &a) { impl::read::all_read(is, a); return is; } template <class OStream, class T, class U, kk2::is_ostream_t<OStream> * = nullptr> OStream &operator<<(OStream &os, const std::pair<T, U> &p) { impl::write::all_write(os, p); return os; } template <class OStream, class T, kk2::is_ostream_t<OStream> * = nullptr> OStream &operator<<(OStream &os, const std::vector<T> &v) { impl::write::all_write(os, v); return os; } template <class OStream, class T, size_t F, kk2::is_ostream_t<OStream> * = nullptr> OStream &operator<<(OStream &os, const std::array<T, F> &a) { impl::write::all_write(os, a); return os; } #endif // KK2_TEMPLATE_IO_UTIL_HPP #ifndef KK2_TEMPLATE_MACROS_HPP #define KK2_TEMPLATE_MACROS_HPP 1 #define rep1(a) for (long long _ = 0; _ < (long long)(a); ++_) #define rep2(i, a) for (long long i = 0; i < (long long)(a); ++i) #define rep3(i, a, b) for (long long i = (a); i < (long long)(b); ++i) #define repi2(i, a) for (long long i = (a) - 1; i >= 0; --i) #define repi3(i, a, b) for (long long i = (a) - 1; i >= (long long)(b); --i) #define overload3(a, b, c, d, ...) d #define rep(...) overload3(__VA_ARGS__, rep3, rep2, rep1)(__VA_ARGS__) #define repi(...) overload3(__VA_ARGS__, repi3, repi2, rep1)(__VA_ARGS__) #define fi first #define se second #define all(p) begin(p), end(p) #endif // KK2_TEMPLATE_MACROS_HPP struct FastIOSetUp { FastIOSetUp() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); } } fast_io_set_up; auto &kin = std::cin; auto &kout = std::cout; auto (*kendl)(std::ostream &) = std::endl<char, std::char_traits<char>>; void Yes(bool b = 1) { kout << (b ? "Yes\n" : "No\n"); } void No(bool b = 1) { kout << (b ? "No\n" : "Yes\n"); } void YES(bool b = 1) { kout << (b ? "YES\n" : "NO\n"); } void NO(bool b = 1) { kout << (b ? "NO\n" : "YES\n"); } void yes(bool b = 1) { kout << (b ? "yes\n" : "no\n"); } void no(bool b = 1) { kout << (b ? "no\n" : "yes\n"); } template <class T, class S> inline bool chmax(T &a, const S &b) { return (a < b ? a = b, 1 : 0); } template <class T, class S> inline bool chmin(T &a, const S &b) { return (a > b ? a = b, 1 : 0); } std::istream &operator>>(std::istream &is, u128 &x) { std::string s; is >> s; x = 0; for (char c : s) { assert('0' <= c && c <= '9'); x = x * 10 + c - '0'; } return is; } std::istream &operator>>(std::istream &is, i128 &x) { std::string s; is >> s; bool neg = s[0] == '-'; x = 0; for (int i = neg; i < (int)s.size(); i++) { assert('0' <= s[i] && s[i] <= '9'); x = x * 10 + s[i] - '0'; } if (neg) x = -x; return is; } std::ostream &operator<<(std::ostream &os, u128 x) { if (x == 0) return os << '0'; std::string s; while (x) { s.push_back('0' + x % 10); x /= 10; } std::reverse(s.begin(), s.end()); return os << s; } std::ostream &operator<<(std::ostream &os, i128 x) { if (x == 0) return os << '0'; if (x < 0) { os << '-'; x = -x; } std::string s; while (x) { s.push_back('0' + x % 10); x /= 10; } std::reverse(s.begin(), s.end()); return os << s; } #endif // KK2_TEMPLATE_PROCON_HPP // #include <kk2/template/debug.hpp> #ifndef KK2_MODINT_MODINT_HPP #define KK2_MODINT_MODINT_HPP 1 #ifndef KK2_TYPE_TRAITS_INTERGRAL_HPP #define KK2_TYPE_TRAITS_INTERGRAL_HPP 1 namespace kk2 { #ifndef _MSC_VER template <typename T> using is_signed_int128 = typename std::conditional<std::is_same<T, __int128_t>::value or std::is_same<T, __int128>::value, std::true_type, std::false_type>::type; template <typename T> using is_unsigned_int128 = typename std::conditional<std::is_same<T, __uint128_t>::value or std::is_same<T, unsigned __int128>::value, std::true_type, std::false_type>::type; template <typename T> using is_integral = typename std::conditional<std::is_integral<T>::value or is_signed_int128<T>::value or is_unsigned_int128<T>::value, std::true_type, std::false_type>::type; template <typename T> using is_signed = typename std::conditional<std::is_signed<T>::value or is_signed_int128<T>::value, std::true_type, std::false_type>::type; template <typename T> using is_unsigned = typename std::conditional<std::is_unsigned<T>::value or is_unsigned_int128<T>::value, std::true_type, std::false_type>::type; template <typename T> using make_unsigned_int128 = typename std::conditional<std::is_same<T, __int128_t>::value, __uint128_t, unsigned __int128>; template <typename T> using to_unsigned = typename std::conditional<is_signed_int128<T>::value, make_unsigned_int128<T>, typename std::conditional<std::is_signed<T>::value, std::make_unsigned<T>, std::common_type<T>>::type>::type; #else template <typename T> using is_integral = std::enable_if_t<std::is_integral<T>::value>; template <typename T> using is_signed = std::enable_if_t<std::is_signed<T>::value>; template <typename T> using is_unsigned = std::enable_if_t<std::is_unsigned<T>::value>; template <typename T> using to_unsigned = std::make_unsigned<T>; #endif // _MSC_VER template <typename T> using is_integral_t = std::enable_if_t<is_integral<T>::value>; template <typename T> using is_signed_t = std::enable_if_t<is_signed<T>::value>; template <typename T> using is_unsigned_t = std::enable_if_t<is_unsigned<T>::value>; } // namespace kk2 #endif // KK2_TYPE_TRAITS_INTERGRAL_HPP namespace kk2 { template <int p> struct ModInt { using mint = ModInt; public: static int Mod; constexpr static unsigned int getmod() { if (p > 0) return p; else return Mod; } static void setmod(int Mod_) { assert(1 <= Mod_); Mod = Mod_; } static mint raw(int v) { mint x; x._v = v; return x; } constexpr ModInt() : _v(0) {} template <class T, is_integral_t<T> * = nullptr> constexpr ModInt(T v) { if constexpr (is_signed<T>::value) { v = v % (long long)(getmod()); if (v < 0) v += getmod(); _v = v; } else if constexpr (is_unsigned<T>::value) { _v = v %= getmod(); } else { ModInt(); } } unsigned int val() const { return _v; } mint &operator++() { _v++; if (_v == getmod()) _v = 0; return *this; } mint &operator--() { if (_v == 0) _v = getmod(); _v--; return *this; } mint operator++(int) { mint result = *this; ++*this; return result; } mint operator--(int) { mint result = *this; --*this; return result; } mint &operator+=(const mint &rhs) { _v += rhs._v; if (_v >= getmod()) _v -= getmod(); return *this; } mint &operator-=(const mint &rhs) { _v += getmod() - rhs._v; if (_v >= getmod()) _v -= getmod(); return *this; } mint &operator*=(const mint &rhs) { unsigned long long z = _v; z *= rhs._v; z %= getmod(); _v = z; return *this; } mint &operator/=(const mint &rhs) { return *this = *this * rhs.inv(); } mint operator+() const { return *this; } mint operator-() const { return mint() - *this; } friend mint operator+(const mint &lhs, const mint &rhs) { return mint(lhs) += rhs; } friend mint operator-(const mint &lhs, const mint &rhs) { return mint(lhs) -= rhs; } friend mint operator*(const mint &lhs, const mint &rhs) { return mint(lhs) *= rhs; } friend mint operator/(const mint &lhs, const mint &rhs) { return mint(lhs) /= rhs; } friend bool operator==(const mint &lhs, const mint &rhs) { return lhs._v == rhs._v; } friend bool operator!=(const mint &lhs, const mint &rhs) { return lhs._v != rhs._v; } mint pow(long long n) const { assert(0 <= n); mint x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; } mint inv() const { long long s = getmod(), t = _v; long long m0 = 0, m1 = 1; while (t) { long long u = s / t; s -= t * u; m0 -= m1 * u; std::swap(s, t); std::swap(m0, m1); } if (m0 < 0) m0 += getmod() / s; return m0; } template <class OStream, is_ostream_t<OStream> * = nullptr> friend OStream &operator<<(OStream &os, const mint &mint_) { os << mint_._v; return os; } template <class IStream, is_istream_t<IStream> * = nullptr> friend IStream &operator>>(IStream &is, mint &mint_) { long long x; is >> x; mint_ = mint(x); return is; } private: unsigned int _v; }; template <int p> int ModInt<p>::Mod = 998244353; using mint998 = ModInt<998244353>; using mint107 = ModInt<1000000007>; } // namespace kk2 #endif // KK2_MODINT_MODINT_HPP #ifndef KK2_FPS_FPS_NTT_FRIENDLY_HPP #define KK2_FPS_FPS_NTT_FRIENDLY_HPP 1 #ifndef KK2_CONVOLUTION_CONVOLUTION_HPP #define KK2_CONVOLUTION_CONVOLUTION_HPP 1 #ifndef KK2_FPS_FPS_SPARSITY_DETECTOR_HPP #define KK2_FPS_FPS_SPARSITY_DETECTOR_HPP 1 #ifndef KK2_BIT_BITCOUNT_HPP #define KK2_BIT_BITCOUNT_HPP 1 namespace kk2 { template <typename T> constexpr int ctz(T x) { static_assert(is_integral<T>::value); assert(x != T(0)); if constexpr (sizeof(T) <= 4) { return __builtin_ctz(x); } else if constexpr (sizeof(T) <= 8) { return __builtin_ctzll(x); } else { if (x & 0xffffffffffffffff) return __builtin_ctzll((unsigned long long)(x & 0xffffffffffffffff)); return 64 + __builtin_ctzll((unsigned long long)(x >> 64)); } } template <typename T> constexpr int lsb(T x) { static_assert(is_integral<T>::value); assert(x != T(0)); return ctz(x); } template <typename T> constexpr int clz(T x) { static_assert(is_integral<T>::value); assert(x != T(0)); if constexpr (sizeof(T) <= 4) { return __builtin_clz(x); } else if constexpr (sizeof(T) <= 8) { return __builtin_clzll(x); } else { if (x >> 64) return __builtin_clzll((unsigned long long)(x >> 64)); return 64 + __builtin_clzll((unsigned long long)(x & 0xffffffffffffffff)); } } template <typename T> constexpr int msb(T x) { static_assert(is_integral<T>::value); assert(x != T(0)); return sizeof(T) * 8 - 1 - clz(x); } template <typename T> constexpr int popcount(T x) { static_assert(is_integral<T>::value); if constexpr (sizeof(T) <= 4) { return __builtin_popcount(x); } else if constexpr (sizeof(T) <= 8) { return __builtin_popcountll(x); } else { return __builtin_popcountll((unsigned long long)(x >> 64)) + __builtin_popcountll((unsigned long long)(x & 0xffffffffffffffff)); } } }; // namespace kk2 #endif // KK2_BIT_BITCOUNT_HPP namespace kk2 { enum class FPSOperation { CONVOLUTION }; template <class FPS, class mint = typename FPS::value_type> bool is_sparse_operation(FPSOperation op, bool is_ntt_friendly, const FPS &a, const FPS &b) { int n = a.size(), m = b.size(); long long not_zero_a = 0, not_zero_b = 0; for (int i = 0; i < n; i++) not_zero_a += a[i] != mint(0); for (int i = 0; i < m; i++) not_zero_b += b[i] != mint(0); if (op == FPSOperation::CONVOLUTION) { // NTT-friendly -> 3 * FFT // Arbitrary -> 9 * FFT // Sparse -> not_zero(a) * not_zero(b) int lg = msb(n + m) / 2 + 1; return (n + m) * lg * (is_ntt_friendly ? 3 : 7) > not_zero_a * not_zero_b; } return false; } } // namespace kk2 #endif // KK2_FPS_FPS_SPARSITY_DETECTOR_HPP #ifndef KK2_MATH_MOD_BUTTERFLY_HPP #define KK2_MATH_MOD_BUTTERFLY_HPP 1 #ifndef KK2_MATH_MOD_PRIMITIVE_ROOT_HPP #define KK2_MATH_MOD_PRIMITIVE_ROOT_HPP 1 #ifndef KK2_MATH_MOD_POW_MOD_HPP #define KK2_MATH_MOD_POW_MOD_HPP 1 namespace kk2 { template <class S, class T, class U> constexpr S pow_mod(T x, U n, T m) { assert(n >= 0); if (m == 1) return S(0); S _m = m, r = 1; S y = x % _m; if (y < 0) y += _m; while (n) { if (n & 1) r = (r * y) % _m; if (n >>= 1) y = (y * y) % _m; } return r; } } // namespace kk2 #endif // KK2_MATH_MOD_POW_MOD_HPP namespace kk2 { constexpr int primitive_root_constexpr(int m) { if (m == 2) return 1; if (m == 167772161) return 3; if (m == 469762049) return 3; if (m == 754974721) return 11; if (m == 998244353) return 3; if (m == 1107296257) return 10; int divs[20] = {}; divs[0] = 2; int cnt = 1; int x = (m - 1) / 2; while (x % 2 == 0) x /= 2; for (int i = 3; (long long)(i)*i <= x; i += 2) { if (x % i == 0) { divs[cnt++] = i; while (x % i == 0) { x /= i; } } } if (x > 1) { divs[cnt++] = x; } for (int g = 2;; g++) { bool ok = true; for (int i = 0; i < cnt; i++) { if (pow_mod<long long>(g, (m - 1) / divs[i], m) == 1) { ok = false; break; } } if (ok) return g; } } template <int m> static constexpr int primitive_root = primitive_root_constexpr(m); } // namespace kk2 #endif // KK2_MATH_MOD_PRIMITIVE_ROOT_HPP namespace kk2 { template <class FPS, class mint = typename FPS::value_type> void butterfly(FPS &a) { static int g = primitive_root<mint::getmod()>; int n = int(a.size()); int h = 0; while ((1U << h) < (unsigned int)(n)) h++; static bool first = true; static mint sum_e2[30]; // sum_e[i] = ies[0] * ... * ies[i - 1] * es[i] static mint sum_e3[30]; static mint es[30], ies[30]; // es[i]^(2^(2+i)) == 1 if (first) { first = false; int cnt2 = __builtin_ctz(mint::getmod() - 1); mint e = mint(g).pow((mint::getmod() - 1) >> cnt2), ie = e.inv(); for (int i = cnt2; i >= 2; i--) { // e^(2^i) == 1 es[i - 2] = e; ies[i - 2] = ie; e *= e; ie *= ie; } mint now = 1; for (int i = 0; i <= cnt2 - 2; i++) { sum_e2[i] = es[i] * now; now *= ies[i]; } now = 1; for (int i = 0; i <= cnt2 - 3; i++) { sum_e3[i] = es[i + 1] * now; now *= ies[i + 1]; } } int len = 0; while (len < h) { if (h - len == 1) { int p = 1 << (h - len - 1); mint rot = 1; for (int s = 0; s < (1 << len); s++) { int offset = s << (h - len); for (int i = 0; i < p; i++) { auto l = a[i + offset]; auto r = a[i + offset + p] * rot; a[i + offset] = l + r; a[i + offset + p] = l - r; } if (s + 1 != (1 << len)) rot *= sum_e2[__builtin_ctz(~(unsigned int)(s))]; } len++; } else { int p = 1 << (h - len - 2); mint rot = 1, imag = es[0]; for (int s = 0; s < (1 << len); s++) { mint rot2 = rot * rot; mint rot3 = rot2 * rot; int offset = s << (h - len); for (int i = 0; i < p; i++) { auto a0 = a[i + offset]; auto a1 = a[i + offset + p] * rot; auto a2 = a[i + offset + p * 2] * rot2; auto a3 = a[i + offset + p * 3] * rot3; auto a1na3imag = (a1 - a3) * imag; a[i + offset] = a0 + a2 + a1 + a3; a[i + offset + p] = a0 + a2 - a1 - a3; a[i + offset + p * 2] = a0 - a2 + a1na3imag; a[i + offset + p * 3] = a0 - a2 - a1na3imag; } if (s + 1 != (1 << len)) rot *= sum_e3[__builtin_ctz(~(unsigned int)(s))]; } len += 2; } } } template <class FPS, class mint = typename FPS::value_type> void butterfly_inv(FPS &a) { static constexpr int g = primitive_root<mint::getmod()>; int n = int(a.size()); int h = 0; while ((1U << h) < (unsigned int)(n)) h++; static bool first = true; static mint sum_ie2[30]; // sum_ie[i] = es[0] * ... * es[i - 1] * ies[i] static mint sum_ie3[30]; static mint es[30], ies[30]; // es[i]^(2^(2+i)) == 1 static mint invn[30]; if (first) { first = false; int cnt2 = __builtin_ctz(mint::getmod() - 1); mint e = mint(g).pow((mint::getmod() - 1) >> cnt2), ie = e.inv(); for (int i = cnt2; i >= 2; i--) { // e^(2^i) == 1 es[i - 2] = e; ies[i - 2] = ie; e *= e; ie *= ie; } mint now = 1; for (int i = 0; i <= cnt2 - 2; i++) { sum_ie2[i] = ies[i] * now; now *= es[i]; } now = 1; for (int i = 0; i <= cnt2 - 3; i++) { sum_ie3[i] = ies[i + 1] * now; now *= es[i + 1]; } invn[0] = 1; invn[1] = mint::getmod() / 2 + 1; for (int i = 2; i < 30; i++) invn[i] = invn[i - 1] * invn[1]; } int len = h; while (len) { if (len == 1) { int p = 1 << (h - len); mint irot = 1; for (int s = 0; s < (1 << (len - 1)); s++) { int offset = s << (h - len + 1); for (int i = 0; i < p; i++) { auto l = a[i + offset]; auto r = a[i + offset + p]; a[i + offset] = l + r; a[i + offset + p] = (l - r) * irot; } if (s + 1 != (1 << (len - 1))) irot *= sum_ie2[__builtin_ctz(~(unsigned int)(s))]; } len--; } else { int p = 1 << (h - len); mint irot = 1, iimag = ies[0]; for (int s = 0; s < (1 << ((len - 2))); s++) { mint irot2 = irot * irot; mint irot3 = irot2 * irot; int offset = s << (h - len + 2); for (int i = 0; i < p; i++) { auto a0 = a[i + offset]; auto a1 = a[i + offset + p]; auto a2 = a[i + offset + p * 2]; auto a3 = a[i + offset + p * 3]; auto a2na3iimag = (a2 - a3) * iimag; a[i + offset] = a0 + a1 + a2 + a3; a[i + offset + p] = (a0 - a1 + a2na3iimag) * irot; a[i + offset + p * 2] = (a0 + a1 - a2 - a3) * irot2; a[i + offset + p * 3] = (a0 - a1 - a2na3iimag) * irot3; } if (s + 1 != (1 << (len - 2))) irot *= sum_ie3[__builtin_ctz(~(unsigned int)(s))]; } len -= 2; } } for (int i = 0; i < n; i++) a[i] *= invn[h]; } template <class FPS, class mint = typename FPS::value_type> void doubling(FPS &a) { int n = a.size(); auto b = a; int z = 1; butterfly_inv(b); mint r = 1, zeta = mint(primitive_root<mint::getmod()>).pow((mint::getmod() - 1) / (n << 1)); for (int i = 0; i < n; i++) { b[i] *= r; r *= zeta; } butterfly(b); std::copy(b.begin(), b.end(), std::back_inserter(a)); } } // namespace kk2 #endif // KK2_MATH_MOD_BUTTERFLY_HPP namespace kk2 { template <class FPS, class mint = typename FPS::value_type> FPS convolution(FPS &a, const FPS &b) { int n = int(a.size()), m = int(b.size()); if (!n || !m) return {}; if (is_sparse_operation(FPSOperation::CONVOLUTION, 1, a, b)) { std::vector<int> nza(n), nzb(m); int ai = 0, bi = 0; for (int i = 0; i < n; i++) if (a[i] != mint(0)) nza[ai++] = i; for (int i = 0; i < m; i++) if (b[i] != mint(0)) nzb[bi++] = i; nza.resize(ai), nzb.resize(bi); FPS res(n + m - 1); for (int i : nza) for (int j : nzb) res[i + j] += a[i] * b[j]; return a = res; } int z = 1; while (z < n + m - 1) z <<= 1; if (a == b) { a.resize(z); butterfly(a); for (int i = 0; i < z; i++) a[i] *= a[i]; } else { a.resize(z); butterfly(a); FPS t(b.begin(), b.end()); t.resize(z); butterfly(t); for (int i = 0; i < z; i++) a[i] *= t[i]; } butterfly_inv(a); a.resize(n + m - 1); return a; } } // namespace kk2 #endif // KK2_CONVOLUTION_CONVOLUTION_HPP namespace kk2 { template <class mint> struct FormalPowerSeriesNTTFriendly : std::vector<mint> { using std::vector<mint>::vector; using FPS = FormalPowerSeriesNTTFriendly; template <class OStream, is_ostream_t<OStream> * = nullptr> void debug_output(OStream &os) const { os << "["; for (int i = 0; i < (int)this->size(); i++) { os << (*this)[i] << (i + 1 == (int)this->size() ? "" : ", "); } os << "]"; } template <class OStream, is_ostream_t<OStream> * = nullptr> void output(OStream &os) const { for (int i = 0; i < (int)this->size(); i++) { os << (*this)[i] << (i + 1 == (int)this->size() ? "\n" : " "); } } template <class OStream, is_ostream_t<OStream> * = nullptr> friend OStream &operator<<(OStream &os, const FPS &fps_) { for (int i = 0; i < (int)fps_.size(); i++) { os << fps_[i] << (i + 1 == (int)fps_.size() ? "" : " "); } return os; } template <class IStream, is_istream_t<IStream> * = nullptr> FPS &input(IStream &is) { for (int i = 0; i < (int)this->size(); i++) is >> (*this)[i]; return *this; } template <class IStream, is_istream_t<IStream> * = nullptr> friend IStream &operator>>(IStream &is, FPS &fps_) { for (auto &x : fps_) is >> x; return is; } FPS &operator+=(const FPS &r) { if (this->size() < r.size()) this->resize(r.size()); for (int i = 0; i < (int)r.size(); i++) (*this)[i] += r[i]; return *this; } FPS &operator+=(const mint &r) { if (this->empty()) this->resize(1); (*this)[0] += r; return *this; } FPS &operator-=(const FPS &r) { if (this->size() < r.size()) this->resize(r.size()); for (int i = 0; i < (int)r.size(); i++) (*this)[i] -= r[i]; return *this; } FPS &operator-=(const mint &r) { if (this->empty()) this->resize(1); (*this)[0] -= r; return *this; } FPS &operator*=(const mint &r) { for (int i = 0; i < (int)this->size(); i++) { (*this)[i] *= r; } return *this; } FPS &operator/=(const FPS &r) { assert(!r.empty()); if (this->size() < r.size()) { this->clear(); return *this; } int n = this->size() - r.size() + 1; if ((int)r.size() <= 64) { FPS f(*this), g(r); g.shrink(); mint coeff = g.back().inv(); for (auto &x : g) x *= coeff; int deg = (int)f.size() - (int)g.size() + 1; int gs = g.size(); FPS quo(deg); for (int i = deg - 1; i >= 0; i--) { quo[i] = f[i + gs - 1]; for (int j = 0; j < gs; j++) f[i + j] -= quo[i] * g[j]; } *this = quo * coeff; this->resize(n, mint(0)); return *this; } return *this = ((*this).rev().pre(n) * r.rev().inv(n)).pre(n).rev(); } FPS &operator%=(const FPS &r) { *this -= *this / r * r; shrink(); return *this; } FPS operator+(const FPS &r) const { return FPS(*this) += r; } FPS operator+(const mint &r) const { return FPS(*this) += r; } FPS operator-(const FPS &r) const { return FPS(*this) -= r; } FPS operator-(const mint &r) const { return FPS(*this) -= r; } FPS operator*(const mint &r) const { return FPS(*this) *= r; } FPS operator/(const FPS &r) const { return FPS(*this) /= r; } FPS operator%(const FPS &r) const { return FPS(*this) %= r; } FPS operator-() const { FPS ret(this->size()); for (int i = 0; i < (int)this->size(); i++) ret[i] = -(*this)[i]; return ret; } FPS &shrink() { while (this->size() && this->back() == mint(0)) this->pop_back(); return *this; } FPS rev() const { FPS ret(*this); std::reverse(ret.begin(), ret.end()); return ret; } FPS &inplace_rev() { std::reverse(this->begin(), this->end()); return *this; } FPS dot(const FPS &r) const { FPS ret(std::min(this->size(), r.size())); for (int i = 0; i < (int)ret.size(); i++) ret[i] = (*this)[i] * r[i]; return ret; } FPS &inplace_dot(const FPS &r) { this->resize(std::min(this->size(), r.size())); for (int i = 0; i < (int)this->size(); i++) (*this)[i] *= r[i]; return *this; } FPS pre(int n) const { FPS ret(this->begin(), this->begin() + std::min((int)this->size(), n)); if ((int)ret.size() < n) ret.resize(n, mint(0)); return ret; } FPS &inplace_pre(int n) { this->resize(n); return *this; } FPS operator>>(int n) const { if (n >= (int)this->size()) return {}; FPS ret(this->begin() + n, this->end()); return ret; } FPS operator<<(int n) const { FPS ret(*this); ret.insert(ret.begin(), n, mint(0)); return ret; } FPS diff() const { const int n = (int)this->size(); FPS ret(std::max(0, n - 1)); for (int i = 1; i < n; i++) { ret[i - 1] = (*this)[i] * mint(i); } return ret; } FPS &inplace_diff() { if (this->empty()) return *this = FPS(); this->erase(this->begin()); for (int i = 1; i <= (int)this->size(); i++) (*this)[i - 1] *= mint(i); return *this; } FPS integral() const { const int n = (int)this->size(); FPS ret(n + 1); ret[0] = mint(0); if (n > 0) ret[1] = mint(1); auto mod = mint::getmod(); for (int i = 2; i <= n; i++) { // p = q * i + r // - q / r = 1 / i (mod p) ret[i] = (-ret[mod % i]) * (mod / i); } for (int i = 0; i < n; i++) { ret[i + 1] *= (*this)[i]; } return ret; } FPS &inplace_int() { static std::vector<mint> inv{0, 1}; const int n = this->size(); auto mod = mint::getmod(); while ((int)inv.size() <= n) { // p = q * i + r // - q / r = 1 / i (mod p) int i = inv.size(); inv.push_back((-inv[mod % i]) * (mod / i)); } this->insert(this->begin(), mint(0)); for (int i = 1; i <= n; i++) (*this)[i] *= inv[i]; return *this; } mint eval(mint x) const { mint r = 0, w = 1; for (auto &v : *this) { r += w * v; w *= x; } return r; } FPS log(int deg = -1) const { assert(!this->empty() && (*this)[0] == mint(1)); if (deg == -1) deg = this->size(); return (this->diff() * this->inv(deg)).pre(deg - 1).integral(); } FPS sparse_log(int deg = -1) const { assert(!this->empty() && (*this)[0] == mint(1)); if (deg == -1) deg = this->size(); std::vector<std::pair<int, mint>> fs; for (int i = 1; i < int(this->size()); i++) { if ((*this)[i] != mint(0)) fs.emplace_back(i, (*this)[i]); } int mod = mint::getmod(); static std::vector<mint> inv{1, 1}; while ((int)inv.size() <= deg) { int i = inv.size(); inv.push_back(-inv[mod % i] * (mod / i)); } FPS g(deg); for (int k = 0; k < deg - 1; k++) { for (auto &[j, fj] : fs) { if (k < j) break; int i = k - j; g[k + 1] -= g[i + 1] * fj * (i + 1); } g[k + 1] *= inv[k + 1]; if (k + 1 < int(this->size())) g[k + 1] += (*this)[k + 1]; } return g; } template <class T> FPS pow(T k, int deg = -1) const { const int n = this->size(); if (deg == -1) deg = n; if (k == 0) { FPS ret(deg); if (deg > 0) ret[0] = mint(1); return ret; } for (int i = 0; i < n; i++) { if ((*this)[i] != mint(0)) { mint rev = mint(1) / (*this)[i]; FPS ret = (((*this * rev) >> i).log(deg) * k).exp(deg); ret *= (*this)[i].pow(k); ret = (ret << (i * k)).pre(deg); if ((int)ret.size() < deg) ret.resize(deg, mint(0)); return ret; } if (__int128_t(i + 1) * k >= deg) return FPS(deg, mint(0)); } return FPS(deg, mint(0)); } template <class T> FPS sparse_pow(T k, int deg = -1) const { if (deg == -1) deg = this->size(); if (k == 0) { FPS ret(deg); if (deg > 0) ret[0] = mint(1); return ret; } int zero = 0; while (zero != int(this->size()) && (*this)[zero] == mint(0)) zero++; if (zero == int(this->size()) || __int128_t(zero) * k >= deg) { return FPS(deg, mint(0)); } if (zero != 0) { FPS suf(this->begin() + zero, this->end()); auto g = suf.sparse_pow(k, deg - zero * k); FPS ret(zero * k, mint(0)); std::copy(std::begin(g), std::end(g), std::back_inserter(ret)); return ret; } int mod = mint::getmod(); static std::vector<mint> inv{1, 1}; while ((int)inv.size() <= deg) { int i = inv.size(); inv.push_back(-inv[mod % i] * (mod / i)); } std::vector<std::pair<int, mint>> fs; for (int i = 1; i < int(this->size()); i++) { if ((*this)[i] != mint(0)) fs.emplace_back(i, (*this)[i]); } FPS g(deg); g[0] = (*this)[0].pow(k); mint denom = (*this)[0].inv(); k %= mod; for (int a = 1; a < deg; a++) { for (auto &[i, f_i] : fs) { if (a < i) break; g[a] += g[a - i] * f_i * (mint(i) * (k + 1) - a); } g[a] *= denom * inv[a]; } return g; } // assume that r is sparse // return this / r FPS sparse_div(const FPS &r, int deg = -1) const { assert(!r.empty() && r[0] != mint(0)); if (deg == -1) deg = this->size(); mint ir0 = r[0].inv(); FPS ret = *this * ir0; ret.resize(deg); std::vector<std::pair<int, mint>> gs; for (int i = 1; i < (int)r.size(); i++) { if (r[i] != mint(0)) gs.emplace_back(i, r[i] * ir0); } for (int i = 0; i < deg; i++) { for (auto &[j, g_j] : gs) { if (i + j >= deg) break; ret[i + j] -= ret[i] * g_j; } } return ret; } FPS sparse_inv(int deg = -1) const { assert(!this->empty() && (*this)[0] != mint(0)); if (deg == -1) deg = this->size(); std::vector<std::pair<int, mint>> fs; for (int i = 1; i < int(this->size()); i++) { if ((*this)[i] != mint(0)) fs.emplace_back(i, (*this)[i]); } FPS ret(deg); mint if0 = (*this)[0].inv(); if (0 < deg) ret[0] = if0; for (int k = 1; k < deg; k++) { for (auto &[j, fj] : fs) { if (k < j) break; ret[k] += ret[k - j] * fj; } ret[k] *= -if0; } return ret; } FPS sparse_exp(int deg = -1) const { assert(this->empty() || (*this)[0] == mint(0)); if (deg == -1) deg = this->size(); std::vector<std::pair<int, mint>> fs; for (int i = 1; i < int(this->size()); i++) { if ((*this)[i] != mint(0)) fs.emplace_back(i, (*this)[i]); } int mod = mint::getmod(); static std::vector<mint> inv{1, 1}; while ((int)inv.size() <= deg) { int i = inv.size(); inv.push_back(-inv[mod % i] * (mod / i)); } FPS g(deg); if (deg) g[0] = 1; for (int k = 0; k < deg - 1; k++) { for (auto &[ip1, fip1] : fs) { int i = ip1 - 1; if (k < i) break; g[k + 1] += g[k - i] * fip1 * (i + 1); } g[k + 1] *= inv[k + 1]; } return g; } FPS &inplace_imos(int n) { inplace_pre(n); for (int i = 0; i < n - 1; i++) { (*this)[i + 1] += (*this)[i]; } return *this; } FPS imos(int n) const { FPS ret(*this); return ret.inplace_imos(n); } FPS &inplace_iimos(int n) { inplace_pre(n); for (int i = 0; i < n - 1; i++) { (*this)[i + 1] -= (*this)[i]; } return *this; } FPS iimos(int n) const { FPS ret(*this); return ret.inplace_iimos(n); } FPS &operator*=(const FPS &r); FPS operator*(const FPS &r) const { return FPS(*this) *= r; } void but(); void ibut(); void db(); static int but_pr(); FPS inv(int deg = -1) const; FPS exp(int deg = -1) const; }; template <class mint> FormalPowerSeriesNTTFriendly<mint> & FormalPowerSeriesNTTFriendly<mint>::operator*=(const FormalPowerSeriesNTTFriendly<mint> &r) { if (this->empty() || r.empty()) { this->clear(); return *this; } convolution(*this, r); return *this; } template <class mint> void FormalPowerSeriesNTTFriendly<mint>::but() { butterfly(*this); } template <class mint> void FormalPowerSeriesNTTFriendly<mint>::ibut() { butterfly_inv(*this); } template <class mint> void FormalPowerSeriesNTTFriendly<mint>::db() { doubling(*this); } template <class mint> int FormalPowerSeriesNTTFriendly<mint>::but_pr() { return primitive_root<mint::getmod()>; } template <class mint> FormalPowerSeriesNTTFriendly<mint> FormalPowerSeriesNTTFriendly<mint>::inv(int deg) const { assert((*this)[0] != mint(0)); if (deg == -1) deg = (int)this->size(); FormalPowerSeriesNTTFriendly<mint> res(deg); res[0] = {mint(1) / (*this)[0]}; for (int d = 1; d < deg; d <<= 1) { FormalPowerSeriesNTTFriendly<mint> f(2 * d), g(2 * d); std::copy(std::begin(*this), std::begin(*this) + std::min((int)this->size(), 2 * d), std::begin(f)); std::copy(std::begin(res), std::begin(res) + d, std::begin(g)); f.but(); g.but(); f.inplace_dot(g); f.ibut(); std::fill(std::begin(f), std::begin(f) + d, mint(0)); f.but(); f.inplace_dot(g); f.ibut(); for (int j = d; j < std::min(2 * d, deg); j++) res[j] = -f[j]; } return res.pre(deg); } template <class mint> FormalPowerSeriesNTTFriendly<mint> FormalPowerSeriesNTTFriendly<mint>::exp(int deg) const { assert(this->empty() || (*this)[0] == mint(0)); if (deg == -1) deg = (int)this->size(); FormalPowerSeriesNTTFriendly<mint> inv; inv.reserve(deg + 1); inv.push_back(mint(0)); inv.push_back(mint(1)); FormalPowerSeriesNTTFriendly<mint> b{1, 1 < (int)this->size() ? (*this)[1] : mint(0)}; FormalPowerSeriesNTTFriendly<mint> c{1}, z1, z2{1, 1}; for (int m = 2; m < deg; m <<= 1) { auto y = b; y.resize(m << 1); y.but(); z1 = z2; FormalPowerSeriesNTTFriendly<mint> z(m); z = y.dot(z1); z.ibut(); std::fill(std::begin(z), std::begin(z) + (m >> 1), mint(0)); z.but(); z.inplace_dot(-z1); z.ibut(); c.insert(std::end(c), std::begin(z) + (m >> 1), std::end(z)); z2 = c; z2.resize(m << 1); z2.but(); FormalPowerSeriesNTTFriendly<mint> x(this->begin(), this->begin() + std::min<int>(this->size(), m)); x.resize(m); x.inplace_diff(); x.push_back(mint(0)); x.but(); x.inplace_dot(y); x.ibut(); x -= b.diff(); x.resize(m << 1); for (int i = 0; i < m - 1; i++) { x[m + i] = x[i]; x[i] = mint(0); } x.but(); x.inplace_dot(z2); x.ibut(); x.pop_back(); x.inplace_int(); for (int i = m; i < std::min<int>(this->size(), m << 1); i++) x[i] += (*this)[i]; std::fill(std::begin(x), std::begin(x) + m, mint(0)); x.but(); x.inplace_dot(y); x.ibut(); b.insert(std::end(b), std::begin(x) + m, std::end(x)); } return FormalPowerSeriesNTTFriendly<mint>(std::begin(b), std::begin(b) + deg); } template <class mint> using FPSNTT = FormalPowerSeriesNTTFriendly<mint>; } // namespace kk2 #endif // KK2_FPS_FPS_NTT_FRIENDLY_HPP using namespace std; void solve() { using mint = kk2::mint998; using fps = kk2::FPSNTT<mint>; int n; kin >> n; mint inv2 = mint(2).inv(); auto mult = [&inv2](const fps &a, const fps &b) -> fps { fps c(a.size() + b.size() - 1); fps tmp = a * b; rep (i, tmp.size()) c[i] = tmp[i] * inv2; fps rb = b.rev(); tmp = a * rb; int m = b.size() - 1; rep (i, tmp.size()) { int j = abs(i - m); c[j] += tmp[i] * inv2; } return c; }; auto rec = [&](auto self, int m) -> fps { if (m == 0) return fps{1}; if (m == 1) return fps{0, 2}; fps a = self(self, m / 2); if (m & 1) return mult(mult(a, a), fps{0, 2}); else return mult(a, a); }; kout << rec(rec, n) << kendl; } int main() { #ifdef KK2 int t = 4; #else int t = 1; #endif // kin >> t; rep (t) solve(); return 0; } // Author: kk2 // converted by https://github.com/kk2a/cpp-bundle // 2025-06-06 21:44:45