結果
問題 | No.2883 K-powered Sum of Fibonacci |
ユーザー |
![]() |
提出日時 | 2025-02-10 01:12:16 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 292 ms / 3,000 ms |
コード長 | 25,119 bytes |
コンパイル時間 | 4,126 ms |
コンパイル使用メモリ | 297,696 KB |
実行使用メモリ | 30,612 KB |
最終ジャッジ日時 | 2025-02-10 01:12:28 |
合計ジャッジ時間 | 12,306 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 40 |
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; using P = pair<long long, long long>; #define rep(i, a, b) for(long long i = (a); i < (b); ++i) #define rrep(i, a, b) for(long long i = (a); i >= (b); --i) constexpr long long inf = 4e18; struct SetupIO { SetupIO() { ios::sync_with_stdio(0); cin.tie(0); cout << fixed << setprecision(30); } } setup_io; template <uint32_t m> struct StaticModint { using mint = StaticModint; static constexpr uint32_t mod() { return m; } static constexpr mint raw(const uint32_t v) { mint a; a._v = v; return a; } constexpr StaticModint() : _v(0) {} template <class T> constexpr StaticModint(const T& v) { static_assert(is_integral_v<T>); if constexpr(is_signed_v<T>) { int64_t x = int64_t(v % int64_t(m)); if(x < 0) x += m; _v = uint32_t(x); } else _v = uint32_t(v % m); } constexpr uint32_t val() const { return _v; } constexpr mint& operator++() { return *this += 1; } constexpr mint& operator--() { return *this -= 1; } constexpr mint operator++(int) { mint res = *this; ++*this; return res; } constexpr mint operator--(int) { mint res = *this; --*this; return res; } constexpr mint& operator+=(mint rhs) { if(_v >= m - rhs._v) _v -= m; _v += rhs._v; return *this; } constexpr mint& operator-=(mint rhs) { if(_v < rhs._v) _v += m; _v -= rhs._v; return *this; } constexpr mint& operator*=(mint rhs) { return *this = *this * rhs; } constexpr mint& operator/=(mint rhs) { return *this *= rhs.inv(); } constexpr mint operator+() const { return *this; } constexpr mint operator-() const { return mint{} - *this; } constexpr mint pow(long long n) const { assert(0 <= n); if(n == 0) return 1; mint x = *this, r = 1; while(1) { if(n & 1) r *= x; n >>= 1; if(n == 0) return r; x *= x; } } constexpr mint inv() const { if constexpr(prime) { assert(_v); return pow(m - 2); } else { const auto eg = inv_gcd(_v, m); assert(eg.first == 1); return eg.second; } } friend constexpr mint operator+(mint lhs, mint rhs) { return lhs += rhs; } friend constexpr mint operator-(mint lhs, mint rhs) { return lhs -= rhs; } friend constexpr mint operator*(mint lhs, mint rhs) { return uint64_t(lhs._v) * rhs._v; } friend constexpr mint operator/(mint lhs, mint rhs) { return lhs /= rhs; } friend constexpr bool operator==(mint lhs, mint rhs) { return lhs._v == rhs._v; } friend constexpr bool operator!=(mint lhs, mint rhs) { return lhs._v != rhs._v; } friend istream& operator>>(istream& in, mint& x) { long long a; in >> a; x = a; return in; } friend ostream& operator<<(ostream& out, const mint& x) { return out << x.val(); } private: uint32_t _v = 0; static constexpr bool prime = []() -> bool { if(m == 1) return 0; if(m == 2 or m == 7 or m == 61) return 1; if(m % 2 == 0) return 0; uint32_t d = m - 1; while(d % 2 == 0) d /= 2; for(uint32_t a : {2, 7, 61}) { uint32_t t = d; mint y = mint(a).pow(t); while(t != m - 1 && y != 1 && y != m - 1) { y *= y; t <<= 1; } if(y != m - 1 && t % 2 == 0) return 0; } return 1; }(); static constexpr pair<int32_t, int32_t> inv_gcd(const int32_t a, const int32_t b) { if(a == 0) return {b, 0}; int32_t s = b, t = a, m0 = 0, m1 = 1; while(t) { const int32_t u = s / t; s -= t * u; m0 -= m1 * u; swap(s, t); swap(m0, m1); } if(m0 < 0) m0 += b / s; return {s, m0}; } }; using modint998244353 = StaticModint<998244353>; using modint1000000007 = StaticModint<1000000007>; using mint = modint998244353; constexpr long long pow_mod(long long x, long long n, const long long mod) { assert(n >= 0 and mod >= 1); x %= mod; if(x < 0) x += mod; long long res = 1; while(n > 0) { if(n & 1) res = res * x % mod; x = x * x % mod; n >>= 1; } return res; } constexpr int primitive_root(const 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; 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(g, (m - 1) / divs[i], m) == 1) { ok = false; break; } } if(ok) return g; } } constexpr int countr_zero(const unsigned int n) { int res = 0; while(!(n & (1 << res))) ++res; return res; } template <typename mint, int g = primitive_root(mint::mod())> struct FFT_Info { static constexpr int rank2 = countr_zero(mint::mod() - 1); array<mint, rank2 + 1> root; array<mint, rank2 + 1> iroot; array<mint, max(0, rank2 - 2 + 1)> rate2; array<mint, max(0, rank2 - 2 + 1)> irate2; array<mint, max(0, rank2 - 3 + 1)> rate3; array<mint, max(0, rank2 - 3 + 1)> irate3; FFT_Info() { root[rank2] = mint(g).pow((mint::mod() - 1) >> rank2); iroot[rank2] = root[rank2].inv(); for(int i = rank2 - 1; i >= 0; --i) { root[i] = root[i + 1] * root[i + 1]; iroot[i] = iroot[i + 1] * iroot[i + 1]; } { mint prod = 1, iprod = 1; for(int i = 0; i <= rank2 - 2; ++i) { rate2[i] = root[i + 2] * prod; irate2[i] = iroot[i + 2] * iprod; prod *= iroot[i + 2]; iprod *= root[i + 2]; } } { mint prod = 1, iprod = 1; for(int i = 0; i <= rank2 - 3; ++i) { rate3[i] = root[i + 3] * prod; irate3[i] = iroot[i + 3] * iprod; prod *= iroot[i + 3]; iprod *= root[i + 3]; } } } }; template <typename mint> void butterfly(vector<mint>& a) { const int n = (int)a.size(); const int h = __builtin_ctz((unsigned int)n); static const FFT_Info<mint> info; int len = 0; while(len < h) { if(h - len == 1) { const int p = 1 << (h - len - 1); mint rot = 1; for(int s = 0; s < (1 << len); ++s) { const int offset = s << (h - len); for(int i = 0; i < p; ++i) { const auto l = a[i + offset]; const auto r = a[i + offset + p] * rot; a[i + offset] = l + r; a[i + offset + p] = l - r; } if(s + 1 != (1 << len)) rot *= info.rate2[__builtin_ctz(~(unsigned int)(s))]; } ++len; } else { const int p = 1 << (h - len - 2); mint rot = 1, imag = info.root[2]; for(int s = 0; s < (1 << len); ++s) { const mint rot2 = rot * rot; const mint rot3 = rot2 * rot; const int offset = s << (h - len); for(int i = 0; i < p; ++i) { const auto mod2 = 1ULL * mint::mod() * mint::mod(); const auto a0 = 1ULL * a[i + offset].val(); const auto a1 = 1ULL * a[i + offset + p].val() * rot.val(); const auto a2 = 1ULL * a[i + offset + 2 * p].val() * rot2.val(); const auto a3 = 1ULL * a[i + offset + 3 * p].val() * rot3.val(); const auto a1na3imag = 1ULL * mint(a1 + mod2 - a3).val() * imag.val(); const auto na2 = mod2 - a2; a[i + offset] = a0 + a2 + a1 + a3; a[i + offset + 1 * p] = a0 + a2 + (2 * mod2 - (a1 + a3)); a[i + offset + 2 * p] = a0 + na2 + a1na3imag; a[i + offset + 3 * p] = a0 + na2 + (mod2 - a1na3imag); } if(s + 1 != (1 << len)) rot *= info.rate3[__builtin_ctz(~(unsigned int)(s))]; } len += 2; } } } template <typename mint> void butterfly_inv(vector<mint>& a) { const int n = (int)a.size(); const int h = __builtin_ctz((unsigned int)n); static const FFT_Info<mint> info; int len = h; while(len) { if(len == 1) { const int p = 1 << (h - len); mint irot = 1; for(int s = 0; s < (1 << (len - 1)); ++s) { const int offset = s << (h - len + 1); for(int i = 0; i < p; ++i) { const auto l = a[i + offset]; const auto r = a[i + offset + p]; a[i + offset] = l + r; a[i + offset + p] = (unsigned long long)(mint::mod() + l.val() - r.val()) * irot.val(); } if(s + 1 != (1 << (len - 1))) irot *= info.irate2[__builtin_ctz(~(unsigned int)(s))]; } --len; } else { const int p = 1 << (h - len); mint irot = 1, iimag = info.iroot[2]; for(int s = 0; s < (1 << (len - 2)); ++s) { const mint irot2 = irot * irot; const mint irot3 = irot2 * irot; const int offset = s << (h - len + 2); for(int i = 0; i < p; ++i) { const auto a0 = 1ULL * a[i + offset + 0 * p].val(); const auto a1 = 1ULL * a[i + offset + 1 * p].val(); const auto a2 = 1ULL * a[i + offset + 2 * p].val(); const auto a3 = 1ULL * a[i + offset + 3 * p].val(); const auto a2na3iimag = 1ULL * mint((mint::mod() + a2 - a3) * iimag.val()).val(); a[i + offset] = a0 + a1 + a2 + a3; a[i + offset + 1 * p] = (a0 + (mint::mod() - a1) + a2na3iimag) * irot.val(); a[i + offset + 2 * p] = (a0 + a1 + (mint::mod() - a2) + (mint::mod() - a3)) * irot2.val(); a[i + offset + 3 * p] = (a0 + (mint::mod() - a1) + (mint::mod() - a2na3iimag)) * irot3.val(); } if(s + 1 != (1 << (len - 2))) irot *= info.irate3[__builtin_ctz(~(unsigned int)(s))]; } len -= 2; } } } template <typename mint> vector<mint> convolution_naive(const vector<mint>& a, const vector<mint>& b) { const int n = (int)a.size(), m = (int)b.size(); vector<mint> res(n + m - 1); if(n < m) { for(int j = 0; j < m; ++j) { for(int i = 0; i < n; ++i) { res[i + j] += a[i] * b[j]; } } } else { for(int i = 0; i < n; ++i) { for(int j = 0; j < m; ++j) { res[i + j] += a[i] * b[j]; } } } return res; } template <typename mint> vector<mint> convolution(vector<mint> a, vector<mint> b) { const int n = (int)a.size(), m = (int)b.size(); if(n == 0 or m == 0) return {}; int z = 1; while(z < n + m - 1) z *= 2; assert((mint::mod() - 1) % z == 0); if(min(n, m) <= 60) return convolution_naive(a, b); a.resize(z); b.resize(z); butterfly(a); butterfly(b); for(int i = 0; i < z; ++i) a[i] *= b[i]; butterfly_inv(a); a.resize(n + m - 1); const mint iz = mint(z).inv(); for(int i = 0; i < n + m - 1; ++i) a[i] *= iz; return a; } template <typename mint> struct FormalPowerSeries : vector<mint> { using vector<mint>::vector; using F = FormalPowerSeries; F& operator=(const vector<mint>& g) { const int n = (*this).size(); const int m = g.size(); if(n < m) (*this).resize(m); for(int i = 0; i < m; ++i) (*this)[i] = g[i]; return (*this); } F& operator-() { const int n = (*this).size(); for(int i = 0; i < n; ++i) (*this)[i] *= -1; return (*this); } F& operator+=(const F& g) { const int n = (*this).size(); const int m = g.size(); if(n < m) (*this).resize(m); for(int i = 0; i < m; ++i) (*this)[i] += g[i]; return (*this); } F& operator+=(const mint& r) { if((*this).empty()) (*this).resize(1, mint(0)); (*this)[0] += r; return (*this); } F& operator-=(const F& g) { const int n = (*this).size(); const int m = g.size(); if(n < m) (*this).resize(m); for(int i = 0; i < m; ++i) (*this)[i] -= g[i]; return (*this); } F& operator-=(const mint& r) { if((*this).empty()) (*this).resize(1, mint(0)); (*this)[0] -= r; return (*this); } F& operator*=(const F& g) { (*this) = convolution((*this), g); return (*this); } F& operator*=(const mint& r) { const int n = (*this).size(); for(int i = 0; i < n; ++i) (*this)[i] *= r; return (*this); } F& operator/=(const F& g) { if((*this).size() < g.size()) { (*this).clear(); return (*this); } const int n = (*this).size() - g.size() + 1; (*this) = ((*this).rev().pre(n) * g.rev().inv(n)).pre(n).rev(); return (*this); } F& operator/=(const mint& r) { const int n = (*this).size(); const mint inv_r = r.inv(); for(int i = 0; i < n; ++i) (*this)[i] *= inv_r; return (*this); } F& operator%=(const F& g) { (*this) -= (*this) / g * g; shrink(); return (*this); } F operator*(const mint& g) const { return F(*this) *= g; } F operator-(const mint& g) const { return F(*this) -= g; } F operator+(const mint& g) const { return F(*this) += g; } F operator/(const mint& g) const { return F(*this) /= g; } F operator*(const F& g) const { return F(*this) *= g; } F operator-(const F& g) const { return F(*this) -= g; } F operator+(const F& g) const { return F(*this) += g; } F operator/(const F& g) const { return F(*this) /= g; } F operator%(const F& g) const { return F(*this) %= g; } F operator<<(const int d) const { F ret(*this); ret.insert(ret.begin(), d, mint(0)); return ret; } F operator>>(const int d) const { const int n = (*this).size(); if(n <= d) return {}; F ret(*this); ret.erase(ret.begin(), ret.begin() + d); return ret; } void shrink() { while(!(*this).empty() and (*this).back() == mint(0)) (*this).pop_back(); } F rev() const { F ret(*this); reverse(begin(ret), end(ret)); return ret; } F pre(const int deg) const { assert(deg >= 0); F ret(begin(*this), begin(*this) + min((int)(*this).size(), deg)); if((int)ret.size() < deg) ret.resize(deg); return ret; } mint eval(const mint& a) const { const int n = (*this).size(); mint x = 1, ret = 0; for(int i = 0; i < n; ++i) { ret += (*this)[i] * x; x *= a; } return ret; } void onemul(const int d, const mint& c, int deg = -1) { assert(deg >= -1); const int n = (*this).size(); if(deg == -1) deg = n + d; if(deg > n) (*this).resize(deg); for(int i = deg - d - 1; i >= 0; --i) { (*this)[i + d] += (*this)[i] * c; } } void onediv(const int d, const mint& c, int deg = -1) { assert(deg >= -1); const int n = (*this).size(); if(deg == -1) deg = n; if(deg > n) (*this).resize(deg + 1); for(int i = 0; i < deg - d; ++i) { (*this)[i + d] -= (*this)[i] * c; } } F diff() const { const int n = (*this).size(); F ret(max(0, n - 1)); for(int i = 1; i < n; ++i) ret[i - 1] = (*this)[i] * i; return ret; } F integral() const { const int n = (*this).size(); static constexpr int mod = mint::mod(); F ret(n + 1); ret[0] = mint(0); if(n > 0) ret[1] = mint(1); for(int i = 2; i <= n; ++i) ret[i] = (-ret[mod % i]) * (mod / i); for(int i = 0; i < n; ++i) ret[i + 1] *= (*this)[i]; return ret; } F inv(int deg = -1) const { assert(deg >= -1); const int n = (*this).size(); assert(n > 0 and (*this)[0] != mint(0)); if(deg == -1) deg = n; F g(1); g[0] = (*this)[0].inv(); while((int)g.size() < deg) { const int m = g.size(); F f(begin(*this), begin(*this) + min(n, 2 * m)); F r(g); f.resize(2 * m); r.resize(2 * m); butterfly(f); butterfly(r); for(int i = 0; i < 2 * m; ++i) f[i] *= r[i]; butterfly_inv(f); f.erase(f.begin(), f.begin() + m); f.resize(2 * m); butterfly(f); for(int i = 0; i < 2 * m; ++i) f[i] *= r[i]; butterfly_inv(f); mint in = mint(2 * m).inv(); in *= -in; for(int i = 0; i < m; ++i) f[i] *= in; g.insert(g.end(), f.begin(), f.begin() + m); } return g.pre(deg); } F log(int deg = -1) const { assert(deg >= -1); const int n = (*this).size(); assert(n > 0 and (*this)[0] == mint(1)); if(deg == -1) deg = n; return ((*this).diff() * (*this).inv(deg)).pre(deg - 1).integral(); } F exp(int deg = -1) const { assert(deg >= -1); const int n = (*this).size(); assert(n == 0 or (*this)[0] == 0); if(deg == -1) deg = n; F Inv; Inv.reserve(deg + 1); Inv.emplace_back(mint(0)); Inv.emplace_back(mint(1)); auto inplace_integral = [&](F& f) -> void { const int n = (int)f.size(); static constexpr int mod = mint::mod(); while((int)Inv.size() <= n) { const int i = Inv.size(); Inv.emplace_back((-Inv[mod % i]) * (mod / i)); } f.insert(begin(f), mint(0)); for(int i = 1; i <= n; ++i) f[i] *= Inv[i]; }; auto inplace_diff = [](F& f) -> void { if(f.empty()) return; f.erase(begin(f)); mint coeff = 1; for(int i = 0; i < (int)f.size(); ++i) { f[i] *= coeff; ++coeff; } }; F b{1, 1 < (int)(*this).size() ? (*this)[1] : 0}, c{1}, z1, z2{1, 1}; for(int m = 2; m < deg; m <<= 1) { auto y = b; y.resize(2 * m); butterfly(y); z1 = z2; F z(m); for(int i = 0; i < m; ++i) z[i] = y[i] * z1[i]; butterfly_inv(z); const mint si = mint(m).inv(); for(int i = 0; i < m; ++i) z[i] *= si; fill(begin(z), begin(z) + m / 2, mint(0)); butterfly(z); for(int i = 0; i < m; ++i) z[i] *= -z1[i]; butterfly_inv(z); for(int i = 0; i < m; ++i) z[i] *= si; c.insert(end(c), begin(z) + m / 2, end(z)); z2 = c; z2.resize(2 * m); butterfly(z2); F x(begin((*this)), begin((*this)) + min<int>((*this).size(), m)); x.resize(m); inplace_diff(x); x.emplace_back(mint(0)); butterfly(x); for(int i = 0; i < m; ++i) x[i] *= y[i]; butterfly_inv(x); for(int i = 0; i < m; ++i) x[i] *= si; x -= b.diff(); x.resize(2 * m); for(int i = 0; i < m - 1; ++i) x[m + i] = x[i], x[i] = mint(0); butterfly(x); for(int i = 0; i < 2 * m; ++i) x[i] *= z2[i]; butterfly_inv(x); const mint si2 = mint(m << 1).inv(); for(int i = 0; i < 2 * m; ++i) x[i] *= si2; x.pop_back(); inplace_integral(x); for(int i = m; i < min<int>((*this).size(), 2 * m); ++i) x[i] += (*this)[i]; fill(begin(x), begin(x) + m, mint(0)); butterfly(x); for(int i = 0; i < 2 * m; ++i) x[i] *= y[i]; butterfly_inv(x); for(int i = 0; i < 2 * m; ++i) x[i] *= si2; b.insert(end(b), begin(x) + m, end(x)); } return b.pre(deg); } F pow(const long long k, int deg = -1) const { assert(deg >= -1); assert(k >= 0); const int n = (*this).size(); if(deg == -1) deg = n; if(k == 0) { F ret(deg); if(deg) ret[0] = 1; return ret; } for(int i = 0; i < n; ++i) { if((*this)[i] != mint(0)) { const mint rev = mint(1) / (*this)[i]; F 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 F(deg, mint(0)); } return F(deg, mint(0)); } F shift(const mint& c) const { const int n = (*this).size(); vector<mint> fact(n), ifact(n); fact[0] = ifact[0] = mint(1); for(int i = 1; i < n; ++i) fact[i] = fact[i - 1] * i; ifact[n - 1] = mint(1) / fact[n - 1]; for(int i = n - 1; i > 1; --i) ifact[i - 1] = ifact[i] * i; F ret(*this); for(int i = 0; i < n; ++i) ret[i] *= fact[i]; ret = ret.rev(); F bs(n, mint(1)); for(int i = 1; i < n; ++i) bs[i] = bs[i - 1] * c * ifact[i] * fact[i - 1]; ret = (ret * bs).pre(n); ret = ret.rev(); for(int i = 0; i < n; ++i) ret[i] *= ifact[i]; return ret; } }; using fps = FormalPowerSeries<mint>; template <template <typename> typename FPS, typename mint> FPS<mint> berlekamp_massey(const FPS<mint>& s) { const int n = (int)s.size(); FPS<mint> b = {mint(-1)}, c = {mint(-1)}; mint y = mint(1); for(int ed = 1; ed <= n; ++ed) { int l = (int)c.size(), m = (int)b.size(); mint x = 0; for(int i = 0; i < l; ++i) x += c[i] * s[ed - l + i]; b.emplace_back(0); ++m; if(x == mint(0)) continue; const mint freq = x / y; if(l < m) { const auto tmp = c; c.insert(begin(c), m - l, mint(0)); for(int i = 0; i < m; ++i) c[m - 1 - i] -= freq * b[m - 1 - i]; b = tmp; y = x; } else { for(int i = 0; i < m; ++i) c[l - 1 - i] -= freq * b[m - 1 - i]; } } c.pop_back(); c = c.rev(); return c; } template <template <typename> typename FPS, typename mint> mint bostan_mori(const FPS<mint>& a, const FPS<mint>& c, long long k) { assert(k >= 0); if(k < (int)a.size()) return a[k]; assert(a.size() >= c.size()); FPS<mint> q = FPS<mint>{1} - (c << 1); FPS<mint> p = (a * q).pre((int)c.size()); if(p.empty()) return 0; while(k > 0) { auto q2 = q; for(int i = 1; i < (int)q2.size(); i += 2) q2[i] = -q2[i]; const auto s = p * q2; const auto t = q * q2; if(k & 1) { for(int i = 1; i < (int)s.size(); i += 2) p[i >> 1] = s[i]; for(int i = 0; i < (int)t.size(); i += 2) q[i >> 1] = t[i]; } else { for(int i = 0; i < (int)s.size(); i += 2) p[i >> 1] = s[i]; for(int i = 0; i < (int)t.size(); i += 2) q[i >> 1] = t[i]; } k >>= 1; } return p[0]; } template <template <typename> typename FPS, typename mint> mint nth_term(const FPS<mint>& s, const long long n) { assert(n >= 0); const FPS<mint> c = berlekamp_massey(s); return bostan_mori(s, c, n); } int main(void) { ll n, k; cin >> n >> k; vector<mint> f(1000000); f[1] = 1, f[2] = 1; rep(i, 3, 1000000) f[i] = f[i - 1] + f[i - 2]; fps s(1000000); rep(i, 1, 1000000) { s[i] = s[i - 1] + f[i].pow(k); } cout << nth_term(s, n) << '\n'; }