結果
問題 | No.2580 Hyperinflation |
ユーザー |
|
提出日時 | 2023-12-08 00:28:03 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 39,095 bytes |
コンパイル時間 | 5,297 ms |
コンパイル使用メモリ | 227,796 KB |
実行使用メモリ | 13,056 KB |
最終ジャッジ日時 | 2024-09-27 02:29:08 |
合計ジャッジ時間 | 11,674 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 15 TLE * 1 -- * 15 |
ソースコード
#include <bit>#include <iostream>#include <vector>#include <atcoder/modint>#include <atcoder/convolution>using mint = atcoder::modint998244353;#include <cassert>#include <vector>namespace suisen {template <typename T, typename SumType, SumType(*e)(), SumType(*append)(SumType, T), typename R, R(*merge)(SumType, SumType)>struct QueueAggregation {using value_type = T;using pointer = T*;using const_pointer = const T*;using reference = T&;using const_reference = const T&;using sum_type = SumType;private:struct QueueAggregationIterator {using difference_type = int;using value_type = T;using pointer = const_pointer;using reference = const_reference;using iterator_category = std::random_access_iterator_tag;private:using fi_iterator_type = typename std::vector<std::pair<value_type, value_type>>::const_reverse_iterator;using se_iterator_type = typename std::vector<std::pair<value_type, value_type>>::const_iterator;public:fi_iterator_type it_l;fi_iterator_type it_l_end;se_iterator_type it_r_begin;se_iterator_type it_r;QueueAggregationIterator& operator++() {if (it_l == it_l_end) ++it_r;else ++it_l;return *this;}QueueAggregationIterator operator++(int) { QueueAggregationIterator ret = *this; ++(*this); return ret; }QueueAggregationIterator& operator--() {if (it_r == it_r_begin) --it_l;else --it_r;return *this;}QueueAggregationIterator operator--(int) { QueueAggregationIterator ret = *this; --(*this); return ret; }QueueAggregationIterator& operator+=(difference_type dif) {if (dif < 0) return *this -= -dif;if (int d = it_l_end - it_l; d < dif) it_l = it_l_end, it_r += dif - d;else it_l += dif;return *this;}friend QueueAggregationIterator operator+(QueueAggregationIterator it, difference_type dif) { it += dif; return it; }friend QueueAggregationIterator operator+(difference_type dif, QueueAggregationIterator it) { it += dif; return it; }QueueAggregationIterator& operator-=(difference_type dif) {if (dif < 0) return *this += -dif;if (int d = it_r - it_r_begin; d < dif) it_r = it_r_begin, it_l -= dif - d;else it_r -= dif;return *this;}friend QueueAggregationIterator operator-(QueueAggregationIterator it, difference_type dif) { it -= dif; return it; }difference_type operator-(const QueueAggregationIterator& rhs) const {difference_type d1 = it_l == it_l_end ? it_r - it_r_begin : it_l - it_l_end;difference_type d2 = rhs.it_l == rhs.it_l_end ? rhs.it_r - rhs.it_r_begin : rhs.it_l - rhs.it_l_end;return d1 - d2;}reference operator[](difference_type i) const { return *((*this) + i); }reference operator*() const { return it_l == it_l_end ? it_r->first : it_l->first; }bool operator!=(const QueueAggregationIterator& rhs) const { return it_l != rhs.it_l or it_r != rhs.it_r; }bool operator==(const QueueAggregationIterator& rhs) const { return not (*this != rhs); }bool operator< (const QueueAggregationIterator& rhs) const { return (*this) - rhs < 0; }bool operator<=(const QueueAggregationIterator& rhs) const { return (*this) - rhs <= 0; }bool operator> (const QueueAggregationIterator& rhs) const { return (*this) - rhs > 0; }bool operator>=(const QueueAggregationIterator& rhs) const { return (*this) - rhs >= 0; }};public:using iterator = QueueAggregationIterator;using const_iterator = iterator;QueueAggregation() = default;template <typename InputIterator, std::enable_if_t<std::is_constructible_v<value_type, typename InputIterator::value_type>, std::nullptr_t>= nullptr>QueueAggregation(InputIterator first, InputIterator last) {for (; first != last; ++first) push_back(*first);}template <typename Container, std::enable_if_t<std::is_constructible_v<value_type, typename Container::value_type>, std::nullptr_t> =nullptr>QueueAggregation(const Container& c): QueueAggregation(std::begin(c), std::end(c)) {}R prod() const {return merge(prod(_st_l), prod(_st_r));}void push_back(const value_type& val) { _st_r.emplace_back(val, append(prod(_st_r), val)); }void pop_front() {if (_st_l.size()) return _st_l.pop_back();const int siz = _st_r.size();assert(siz);for (int i = siz - 1; i > 0; --i) {value_type v = std::move(_st_r[i].first);_st_l.emplace_back(v, append(prod(_st_l), v));}_st_r.clear();}const value_type& front() const { return _st_l.size() ? _st_l.back().first : _st_r.front().first; }const value_type& back() const { return _st_r.size() ? _st_r.back().first : _st_l.front().first; }const value_type& operator[](int i) const {const int k = i - _st_l.size();return k < 0 ? _st_l[~k].first : _st_r[k].first;}int size() const { return _st_l.size() + _st_r.size(); }void clear() { _st_l.clear(), _st_r.clear(); }void shrink_to_fit() { _st_l.shrink_to_fit(), _st_r.shrink_to_fit(); }iterator begin() const { return iterator{ _st_l.rbegin(), _st_l.rend(), _st_r.begin(), _st_r.begin() }; }iterator end() const { return iterator{ _st_l.rend(), _st_l.rend(), _st_r.begin(), _st_r.end() }; }iterator cbegin() const { return begin(); }iterator cend() const { return end(); }private:std::vector<std::pair<value_type, sum_type>> _st_l, _st_r;sum_type prod(const std::vector<std::pair<value_type, sum_type>>& st) const {return st.empty() ? e() : st.back().second;}};} // namespace suisenusing SumType = mint;using ElmType = mint;using RetType = mint;SumType e() { return 1; }SumType append(SumType x, ElmType y) { return x * y; }RetType merge(SumType x, SumType y) { return x * y; }using BinomSWAG = suisen::QueueAggregation<ElmType, SumType, e, append, RetType, merge>;#include <iomanip>#include <iostream>#include <sstream>#include <vector>#include <atcoder/convolution>namespace suisen::internal {template <typename T, typename R = T>std::vector<R> convolution_naive(const std::vector<T>& a, const std::vector<T>& b) {const int n = a.size(), m = b.size();std::vector<R> c(n + m - 1);if (n < m) {for (int j = 0; j < m; j++) for (int i = 0; i < n; i++) c[i + j] += R(a[i]) * b[j];} else {for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) c[i + j] += R(a[i]) * b[j];}return c;}} // namespace suisennamespace suisen {template <typename mint, atcoder::internal::is_modint_t<mint>* = nullptr>std::vector<mint> arbitrary_mod_convolution(const std::vector<mint>& a, const std::vector<mint>& b) {int n = int(a.size()), m = int(b.size());if constexpr (atcoder::internal::is_static_modint<mint>::value) {int maxz = 1;while (not ((mint::mod() - 1) & maxz)) maxz <<= 1;int z = 1;while (z < n + m - 1) z <<= 1;if (z <= maxz) return atcoder::convolution<mint>(a, b);}if (n == 0 or m == 0) return {};if (std::min(n, m) <= 120) return internal::convolution_naive(a, b);static constexpr long long MOD1 = 754974721; // 2^24static constexpr long long MOD2 = 167772161; // 2^25static constexpr long long MOD3 = 469762049; // 2^26static constexpr long long M1M2 = MOD1 * MOD2;static constexpr long long INV_M1_MOD2 = atcoder::internal::inv_gcd(MOD1, MOD2).second;static constexpr long long INV_M1M2_MOD3 = atcoder::internal::inv_gcd(M1M2, MOD3).second;std::vector<int> a2(n), b2(m);for (int i = 0; i < n; ++i) a2[i] = a[i].val();for (int i = 0; i < m; ++i) b2[i] = b[i].val();auto c1 = atcoder::convolution<MOD1>(a2, b2);auto c2 = atcoder::convolution<MOD2>(a2, b2);auto c3 = atcoder::convolution<MOD3>(a2, b2);const long long m1m2 = mint(M1M2).val();std::vector<mint> c(n + m - 1);for (int i = 0; i < n + m - 1; ++i) {// Garner's Algorithm// X = x1 + x2 * m1 + x3 * m1 * m2// x1 = c1[i], x2 = (c2[i] - x1) / m1 (mod m2), x3 = (c3[i] - x1 - x2 * m1) / m2 (mod m3)long long x1 = c1[i];long long x2 = (atcoder::static_modint<MOD2>(c2[i] - x1) * INV_M1_MOD2).val();long long x3 = (atcoder::static_modint<MOD3>(c3[i] - x1 - x2 * MOD1) * INV_M1M2_MOD3).val();c[i] = x1 + x2 * MOD1 + x3 * m1m2;}return c;}std::vector<__uint128_t> convolution_int(const std::vector<int> &a, const std::vector<int> &b) {int n = int(a.size()), m = int(b.size());auto check_nonnegative = [](int e) { return e >= 0; };assert(std::all_of(a.begin(), a.end(), check_nonnegative));assert(std::all_of(b.begin(), b.end(), check_nonnegative));if (n == 0 or m == 0) return {};if (std::min(n, m) <= 120) return internal::convolution_naive<int, __uint128_t>(a, b);static constexpr long long MOD1 = 754974721; // 2^24static constexpr long long MOD2 = 167772161; // 2^25static constexpr long long MOD3 = 469762049; // 2^26static constexpr long long M1M2 = MOD1 * MOD2;static constexpr long long INV_M1_MOD2 = atcoder::internal::inv_gcd(MOD1, MOD2).second;static constexpr long long INV_M1M2_MOD3 = atcoder::internal::inv_gcd(M1M2, MOD3).second;auto c1 = atcoder::convolution<MOD1>(a, b);auto c2 = atcoder::convolution<MOD2>(a, b);auto c3 = atcoder::convolution<MOD3>(a, b);std::vector<__uint128_t> c(n + m - 1);for (int i = 0; i < n + m - 1; ++i) {// Garner's Algorithm// X = x1 + x2 * m1 + x3 * m1 * m2// x1 = c1[i], x2 = (c2[i] - x1) / m1 (mod m2), x3 = (c3[i] - x1 - x2 * m1) / m2 (mod m3)int x1 = c1[i];int x2 = (atcoder::static_modint<MOD2>(c2[i] - x1) * INV_M1_MOD2).val();int x3 = (atcoder::static_modint<MOD3>(c3[i] - x1 - x2 * MOD1) * INV_M1M2_MOD3).val();c[i] = x1 + x2 * MOD1 + __uint128_t(x3) * M1M2;}return c;}} // namespace suisennamespace suisen {struct unsigned_bigint : private std::vector<int> {static constexpr int D = 1000000000;static constexpr int LogD = 9;static inline struct { operator unsigned_bigint() const { return unsigned_bigint{}; }; } const ZERO{};static inline struct { operator unsigned_bigint() const { return unsigned_bigint{ 1 }; }; } const ONE{};unsigned_bigint() : vector() {}template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>unsigned_bigint(T v) {if constexpr (std::is_signed_v<T>) {assert(v >= 0);}for (; v; v /= D) {this->push_back(v % D);}}unsigned_bigint(const std::string& s) : vector() {int siz = s.size();for (int i = siz; i > 0; i -= LogD) {int l = std::max(0, i - LogD);int r = i;int& v = this->emplace_back();for (int j = l; j < r; ++j) {int d = s[j] - '0';assert(0 <= d and d <= 9);v = v * 10 + d;}}}unsigned_bigint(const char* s) : unsigned_bigint(std::string(s)) {}operator bool() const {return not this->empty();}friend bool operator==(const unsigned_bigint& a, const unsigned_bigint& b) {if (a.size() != b.size()) {return false;}for (size_t i = 0; i < a.size(); ++i) {if (a[i] != b[i]) return false;}return true;}friend bool operator!=(const unsigned_bigint& a, const unsigned_bigint& b) {return not (a == b);}friend bool operator<(const unsigned_bigint& a, const unsigned_bigint& b) {if (a.size() != b.size()) {return a.size() < b.size();}for (size_t i = a.size(); i-- > 0;) {if (a[i] != b[i]) return a[i] < b[i];}return false;}friend bool operator<=(const unsigned_bigint& a, const unsigned_bigint& b) {return not (b < a);}friend bool operator>(const unsigned_bigint& a, const unsigned_bigint& b) {return b < a;}friend bool operator>=(const unsigned_bigint& a, const unsigned_bigint& b) {return not (a < b);}friend unsigned_bigint& operator<<=(unsigned_bigint& a, int shamt) {if (a) a.insert(a.begin(), shamt, 0);return a;}friend unsigned_bigint operator<<(unsigned_bigint a, int shamt) {a <<= shamt;return a;}friend unsigned_bigint& operator>>=(unsigned_bigint& a, int shamt) {a.erase(a.begin(), a.begin() + std::min<int>(shamt, a.size()));return a;}friend unsigned_bigint operator>>(unsigned_bigint a, int shamt) {a >>= shamt;return a;}unsigned_bigint& operator++() {return _incr_assign(*this);}unsigned_bigint operator++(int) {unsigned_bigint res = *this;_incr_assign(*this);return res;}unsigned_bigint& operator--() {return _decr_assign(*this);}unsigned_bigint operator--(int) {unsigned_bigint res = *this;_decr_assign(*this);return res;}friend unsigned_bigint& operator+=(unsigned_bigint& a, const unsigned_bigint& b) {return _add_assign(a, b);}friend unsigned_bigint operator+(const unsigned_bigint& a, const unsigned_bigint& b) {unsigned_bigint c = a;c += b;return c;}friend unsigned_bigint& operator-=(unsigned_bigint& a, const unsigned_bigint& b) {return _sub_assign(a, b);}friend unsigned_bigint operator-(const unsigned_bigint& a, const unsigned_bigint& b) {unsigned_bigint c = a;c -= b;return c;}friend unsigned_bigint& operator*=(unsigned_bigint& a, const unsigned_bigint& b) {return a = a * b;}friend unsigned_bigint operator*(const unsigned_bigint& a, const unsigned_bigint& b) {return _mul_fft(a, b);}static std::pair<unsigned_bigint, unsigned_bigint> divmod(unsigned_bigint a, unsigned_bigint b) {return _divmod(a, b);}friend unsigned_bigint& operator/=(unsigned_bigint& a, const unsigned_bigint& b) {return a = a / b;}friend unsigned_bigint operator/(const unsigned_bigint& a, const unsigned_bigint& b) {return divmod(a, b).first;}friend unsigned_bigint& operator%=(unsigned_bigint& a, const unsigned_bigint& b) {return a = a % b;}friend unsigned_bigint operator%(const unsigned_bigint& a, const unsigned_bigint& b) {return divmod(a, b).second;}#define CAST_PRIMITIVE(type) \operator type() const { \type res = 0; \for (auto it = this->rbegin(); it != this->rend(); ++it) { \res = res * D + *it; \} \return res; \} \CAST_PRIMITIVE(unsigned int)CAST_PRIMITIVE(unsigned long)CAST_PRIMITIVE(unsigned long long)CAST_PRIMITIVE(__uint128_t)CAST_PRIMITIVE(float)CAST_PRIMITIVE(double)CAST_PRIMITIVE(long double)#undef CAST_PRIMITIVE#define CAST_SIGNED_INT(type) \operator type() const { \return static_cast<std::make_unsigned_t<type>>(*this); \} \CAST_SIGNED_INT(int)CAST_SIGNED_INT(long)CAST_SIGNED_INT(long long)#undef CAST_SIGNED_INToperator __int128_t() const {return static_cast<__uint128_t>(*this);}operator std::string() const {return _to_string();}friend std::istream& operator>>(std::istream& in, unsigned_bigint& v) {std::string s;in >> s, v = s;return in;}friend std::ostream& operator<<(std::ostream& out, const unsigned_bigint& v) {return out << v._to_string();}private:using std::vector<int>::vector;void _check_leading_zeros() const {assert(this->empty() or this->back());}void _cut_leading_zeros() {while (this->size() and this->back() == 0) this->pop_back();}static unsigned_bigint& _incr_assign(unsigned_bigint& a) {for (int& e : a) {if (++e != D) return a;e -= D;}a.push_back(1);return a;}static unsigned_bigint& _decr_assign(unsigned_bigint& a) {assert(a.size());for (int& e : a) {if (--e >= 0) break;e += D;}a._cut_leading_zeros();return a;}static unsigned_bigint& _add_assign(unsigned_bigint& a, const unsigned_bigint& b) {if (a.size() < b.size()) a.resize(b.size());int carry = 0;for (size_t i = 0; i < a.size(); ++i) {if (i >= b.size()) {if (carry) {++a[i];} else break;} else {a[i] += b[i] + carry;}if (a[i] >= D) {a[i] -= D;carry = 1;} else {carry = 0;}}if (carry) a.push_back(1);return a;}static unsigned_bigint& _sub_assign(unsigned_bigint& a, const unsigned_bigint& b) {assert(a.size() >= b.size());int borrow = 0;for (size_t i = 0; i < a.size(); ++i) {if (i >= b.size()) {if (borrow) {--a[i];} else break;} else {a[i] -= b[i] + borrow;}if (a[i] < 0) {a[i] += D;borrow = 1;} else {borrow = 0;}}assert(not borrow);a._cut_leading_zeros();return a;}unsigned_bigint _cut(int l, int r) const {r = std::min(r, static_cast<int>(this->size()));unsigned_bigint v = l < r ? unsigned_bigint(this->begin() + l, this->begin() + r) : ZERO;v._cut_leading_zeros();return v;}template <typename T>static unsigned_bigint _build(const std::vector<T>& dat) {unsigned_bigint res;T carry = 0;for (auto v : dat) {carry += v;res.push_back(carry % D);carry /= D;}while (carry) {res.push_back(carry % D);carry /= D;}res._cut_leading_zeros();return res;}static unsigned_bigint _mul_naive(const unsigned_bigint& a, const unsigned_bigint& b) {return _build(suisen::internal::convolution_naive<int, __int128_t>(a, b));}static unsigned_bigint _mul_karatsuba(const unsigned_bigint& a, const unsigned_bigint& b) {if (std::min(a.size(), b.size()) <= 64) {return _mul_naive(a, b);}const int m = std::max(a.size(), b.size()) / 2;unsigned_bigint lo_a = a._cut(0, m), hi_a = a._cut(m, a.size());unsigned_bigint lo_b = b._cut(0, m), hi_b = b._cut(m, b.size());unsigned_bigint lo_c = lo_a * lo_b;unsigned_bigint hi_c = hi_a * hi_b;bool neg = true;unsigned_bigint md_a;if (hi_a >= lo_a) md_a = hi_a - lo_a;else md_a = lo_a - hi_a, neg = not neg;unsigned_bigint md_b;if (hi_b >= lo_b) md_b = hi_b - lo_b;else md_b = lo_b - hi_b, neg = not neg;unsigned_bigint md_ab = md_a * md_b;unsigned_bigint md_c = (hi_c << m) + lo_c + hi_c + lo_c._cut(m, lo_c.size());if (neg) md_c -= md_ab;else md_c += md_ab;unsigned_bigint c = (md_c << m) + lo_c._cut(0, m);c._cut_leading_zeros();return c;}static unsigned_bigint _mul_fft(const unsigned_bigint& a, const unsigned_bigint& b) {if (std::min(a.size(), b.size()) <= 64) {return _mul_naive(a, b);}if (std::max(a.size(), b.size()) <= 200) {return _mul_karatsuba(a, b);}return _build(suisen::convolution_int(a, b));}// compare(a, D^k)static int _compare_powD(const unsigned_bigint& a, int k) {const int dA = a.size();if (dA <= k) return -1;if (dA >= k + 2) return +1;if (a[k] != 1) return +1;for (int i = 0; i < k; ++i) {if (a[i]) return +1;}return 0;}static unsigned_bigint _powD(int k) {return ONE << k;}static std::pair<unsigned_bigint, unsigned_bigint> _divmod_int(const unsigned_bigint& a, const unsigned_bigint& b) {assert(b.size() == 1);const int b0 = b.front();unsigned_bigint q;long long r = 0;for (auto it = a.rbegin(); it != a.rend(); ++it) {r = r * D + *it;q.push_back(r / b0);r %= b0;}std::reverse(q.begin(), q.end());q._cut_leading_zeros();return { q, r ? unsigned_bigint{ int(r) } : ZERO };}static std::pair<unsigned_bigint, unsigned_bigint> _divmod_naive(unsigned_bigint& a, unsigned_bigint& b) {if (b.size() == 1) {return _divmod_int(a, b);}if (a < b) {return { ZERO, a };}const unsigned_bigint coef{ D / (b.back() + 1) };a *= coef;b *= coef;assert(2 * b.back() >= D);unsigned_bigint q, r(a.end() - b.size(), a.end());for (int i = a.size() - b.size(); i >= 0; --i) {if (r.size() < b.size()) {q.push_back(0);} else if (r.size() == b.size()) {if (r >= b) {q.push_back(1);r -= b;} else {q.push_back(0);}} else {assert(r.size() == b.size() + 1);int x = (static_cast<long long>(r.end()[-1]) * D + r.end()[-2]) / b.back();unsigned_bigint bx = b * unsigned_bigint{ x };while (bx > r) bx -= b, --x;while (bx + b <= r) bx += b, ++x;q.push_back(x);r = r - bx;}if (i) {r.insert(r.begin(), a[i - 1]);}}std::reverse(q.begin(), q.end());q._cut_leading_zeros();r._cut_leading_zeros();return { q, _divmod_int(r, coef).first };}static std::pair<unsigned_bigint, unsigned_bigint> _divmod_naive(const unsigned_bigint& a, const unsigned_bigint& b) {unsigned_bigint a_ = a, b_ = b;return _divmod_naive(a_, b_);}// floor(D^n/b)static unsigned_bigint _div_powD(int n, unsigned_bigint b) {assert(b.size() and 2 * b.back() >= D);const int dB = b.size();int k = n - dB;while (k > 64) k = (k + 1) >> 1;k = std::min(n, dB + k);unsigned_bigint c = _divmod_naive(_powD(k), b).first;unsigned_bigint bc = b * c;for (; k < n; k = 2 * k - dB) {// loop invariant: c = floor(D^k/B)bc.resize(k + 1);int carry = 0;for (int i = 0; i < k; ++i) {bc[i] = D - bc[i] + (i ? carry - 1 : 0);if (bc[i] >= D) {bc[i] -= D;carry = 1;} else {carry = 0;}}++bc[k];c *= bc;c.erase(c.begin(), c.begin() + dB);bc = b * c;if (_compare_powD(bc + b, 2 * k - dB) <= 0) {++c, bc += b;}assert(_compare_powD(bc + b, 2 * k - dB) > 0);}// c = floor(D^k/b)c >>= k - n;return c;}static std::pair<unsigned_bigint, unsigned_bigint> _divmod(unsigned_bigint a, unsigned_bigint b) {assert(b.size());if (std::min(static_cast<int>(b.size()), static_cast<int>(a.size()) - static_cast<int>(b.size())) <= 64) {return _divmod_naive(a, b);}if (a < b) {return { ZERO, a };}const unsigned_bigint coef{ D / (b.back() + 1) };a *= coef;b *= coef;assert(2 * b.back() >= D);const int dA = a.size(), dB = b.size();if (dA == dB) {return { ONE, _divmod_int(a - b, coef).first };}unsigned_bigint invB = _div_powD(dA, b);unsigned_bigint q = a * invB;q.erase(q.begin(), q.begin() + dA);unsigned_bigint qb = q * b, qb2 = qb + b;if (qb2 <= a) {return { ++q, _divmod_int(a - qb2, coef).first };} else {return { q, _divmod_int(a - qb, coef).first };}}std::string _to_string() const {if (this->empty()) return "0";std::ostringstream oss;auto it = this->rbegin();oss << *it;while (++it != this->rend()) {oss << std::setw(9) << std::setfill('0') << *it;}return oss.str();}};} // namespace suisennamespace suisen {struct bigint {static inline struct { operator bigint() const { return bigint{ unsigned_bigint::ZERO }; }; } const ZERO{};static inline struct { operator bigint() const { return bigint{ unsigned_bigint::ONE }; }; } const ONE{};bigint() : _neg(false), _dat{} {}template <typename T, std::enable_if_t<std::is_integral_v<T>, std::nullptr_t> = nullptr>bigint(T v) {_neg = false;if constexpr (std::is_signed_v<T>) {if (v < 0) {_neg = true;v = -v;}}_dat = unsigned_bigint(v);}bigint(const std::string& s) {if (s.front() == '-') {_neg = true;_dat = unsigned_bigint(s.substr(1));fix_sign();} else {_neg = false;_dat = unsigned_bigint(s);}}bigint(const char* s) : bigint(std::string(s)) {}bigint(const unsigned_bigint& dat) : _neg(false), _dat(dat) {}bigint(unsigned_bigint&& dat) : _neg(false), _dat(std::move(dat)) {}operator bool() const {return bool(_dat);}friend bool operator==(const bigint& a, const bigint& b) {if (a._neg xor b._neg) {return false;} else {return a._dat == b._dat;}}friend bool operator!=(const bigint& a, const bigint& b) {return not (a == b);}friend bool operator<(const bigint& a, const bigint& b) {if (a._neg xor b._neg) {return a._neg;} else if (a._neg) {return a._dat > b._dat;} else {return a._dat < b._dat;}}friend bool operator<=(const bigint& a, const bigint& b) {return not (b < a);}friend bool operator>(const bigint& a, const bigint& b) {return b < a;}friend bool operator>=(const bigint& a, const bigint& b) {return not (a < b);}friend bigint& operator<<=(bigint& a, int shamt) {a._dat <<= shamt;return a;}friend bigint operator<<(bigint a, int shamt) {a <<= shamt;return a;}friend bigint& operator>>=(bigint& a, int shamt) {a._dat >>= shamt;a.fix_sign();return a;}friend bigint operator>>(bigint a, int shamt) {a >>= shamt;a.fix_sign();return a;}bigint operator+() const {return *this;}bigint operator-() const {return bigint(_dat, not _neg);}bigint& operator++() {if (_neg) {--_dat;fix_sign();} else {++_dat;}return *this;}bigint operator++(int) {bigint res = *this;++*this;return res;}bigint& operator--() {if (_neg) {++_dat;} else if (_dat) {--_dat;} else {_neg = true;_dat = unsigned_bigint::ONE;}return *this;}bigint operator--(int) {bigint res = *this;--*this;return res;}friend bigint& operator+=(bigint& a, const bigint& b) {if (a._neg xor b._neg) {if (a._dat >= b._dat) {a._dat -= b._dat;} else {a._dat = b._dat - a._dat;a._neg = not a._neg;}a.fix_sign();} else {a._dat += b._dat;}return a;}friend bigint operator+(const bigint& a, const bigint& b) {bigint c = a;c += b;return c;}friend bigint& operator-=(bigint& a, const bigint& b) {if (a._neg xor b._neg) {a._dat += b._dat;} else {if (a._dat >= b._dat) {a._dat -= b._dat;} else {a._dat = b._dat - a._dat;a._neg = not a._neg;}a.fix_sign();}return a;}friend bigint operator-(const bigint& a, const bigint& b) {bigint c = a;c -= b;return c;}friend bigint& operator*=(bigint& a, const bigint& b) {return a = a * b;}friend bigint operator*(const bigint& a, const bigint& b) {return bigint(a._dat * b._dat, a._neg xor b._neg);}static std::pair<bigint, bigint> divmod(bigint a, bigint b) {auto [q, r] = unsigned_bigint::divmod(a._dat, b._dat);return { bigint(std::move(q), a._neg xor b._neg), bigint(std::move(r), a._neg) };}friend bigint& operator/=(bigint& a, const bigint& b) {return a = a / b;}friend bigint operator/(const bigint& a, const bigint& b) {return divmod(a, b).first;}friend bigint& operator%=(bigint& a, const bigint& b) {return a = a % b;}friend bigint operator%(const bigint& a, const bigint& b) {return divmod(a, b).second;}#define CAST_PRIMITIVE(type) \operator type() const { \type res = _dat; \return _neg ? -res : res; \} \CAST_PRIMITIVE(unsigned int)CAST_PRIMITIVE(unsigned long)CAST_PRIMITIVE(unsigned long long)CAST_PRIMITIVE(__uint128_t)CAST_PRIMITIVE(float)CAST_PRIMITIVE(double)CAST_PRIMITIVE(long double)#undef CAST_PRIMITIVE#define CAST_SIGNED_INT(type) \operator type() const { \return static_cast<std::make_unsigned_t<type>>(*this); \} \CAST_SIGNED_INT(int)CAST_SIGNED_INT(long)CAST_SIGNED_INT(long long)#undef CAST_SIGNED_INToperator __int128_t() const {return static_cast<__uint128_t>(*this);}operator unsigned_bigint() const {assert(not _neg);return _dat;}operator std::string() const {if (_neg) {return '-' + std::string(_dat);} else {return std::string(_dat);}}friend std::istream& operator>>(std::istream& in, bigint& v) {std::string s;in >> s, v = s;return in;}friend std::ostream& operator<<(std::ostream& out, const bigint& v) {return out << std::string(v);}private:bigint(const unsigned_bigint& dat, bool neg) : _neg(neg), _dat(dat) { fix_sign(); }bigint(unsigned_bigint&& dat, bool neg) : _neg(neg), _dat(std::move(dat)) { fix_sign(); }bool _neg;unsigned_bigint _dat;void fix_sign() {if (_neg and not _dat) _neg = false;}};} // namespace suisenusing suisen::bigint;mint solve(int N, std::vector<bigint> &A, bigint M) {std::vector<bigint> Mt(N + 1);Mt[N] = M;for (int i = N - 1; i >= 0; --i) {Mt[i] = Mt[i + 1] / A[i];}std::vector binom_table(N + 2, std::vector<mint>(N + 2));for (int i = 0; i <= N + 1; ++i) {binom_table[i][0] = 1;for (int j = 1; j <= i; ++j) {binom_table[i][j] = binom_table[i - 1][j - 1] + binom_table[i - 1][j];}}std::vector<mint> pd(N + 1);for (int x = 0; x <= N; ++x) {auto binom = [](bigint n, int r) -> mint {if (r < 0 or bigint(r) > n) return 0;mint n2 = (int) bigint::divmod(n, mint::mod()).second;mint num = 1, den = 1;for (int i = 0; i < r; ++i) {num *= n2 - i;den *= 1 + i;}return num / den;};pd[x] = binom(bigint(N + 1) + (Mt[0] - bigint(x)), N + 1);}const int z = 1 << std::bit_width<unsigned>(2 * N);const mint iz = mint(z).inv();std::vector bs(N + 1, std::vector<mint>(N + 1));for (int t = 1; t <= N; ++t) if (const bigint At = A[t - 1]; At != bigint(1)) {// x_i,...,x_n < Atconst int u = N - t + 1;const bigint Rt = Mt[t] % At;std::vector<mint> dp(N + 1);// 60 * N * N * log Nmint fac_t_inv = 1;for (int t = 1; t <= u; ++t) fac_t_inv *= t;fac_t_inv = fac_t_inv.inv();for (int i = 0; i <= N; ++i) {// (R_t-x+kA_t)+u ... (R_t-x+kA_t)+1// init: (Rt+kr)+u ... (Rt+kr)+1BinomSWAG binom;for (bigint v = Rt + bigint(i) * At + bigint(u); v >= Rt + bigint(i) * At + bigint(1); --v) {binom.push_back(int(v % bigint(mint::mod())));}for (int d = 0; d <= N; ++d) {bs[d][i] = binom.prod() * fac_t_inv;mint nxt_back = binom.back() - 1;binom.push_back(nxt_back);binom.pop_front();}}std::vector<mint> a(z);for (int i = 0; i <= N; ++i) {a[i] = (i & 1 ? -1 : 1) * binom_table[u + 1][i];}atcoder::internal::butterfly(a);for (int x = 0; x <= N; ++x) {bs[x].resize(z);atcoder::internal::butterfly(bs[x]);for (int t = 0; t < z; ++t) bs[x][t] *= a[t] * iz;atcoder::internal::butterfly_inv(bs[x]);for (int y = 0; y <= N; ++y) dp[x] += bs[x][y] * pd[y];bs[x].resize(N + 1);}pd.swap(dp);}return pd[0];}int main() {int N;std::cin >> N;--N;std::vector<bigint> A(N);for (auto& e : A) std::cin >> e;std::reverse(A.begin(), A.end());bigint M;std::cin >> M;std::cout << (solve(N, A, M) - solve(N, A, M - bigint(1))).val() << std::endl;}