結果
| 問題 |
No.137 貯金箱の焦り
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2024-08-11 16:13:03 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 811 ms / 5,000 ms |
| コード長 | 27,310 bytes |
| コンパイル時間 | 1,711 ms |
| コンパイル使用メモリ | 158,444 KB |
| 実行使用メモリ | 5,376 KB |
| 最終ジャッジ日時 | 2024-08-11 16:13:09 |
| 合計ジャッジ時間 | 6,226 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 23 |
ソースコード
//Timestamp: 2024-08-11 15:12:19
#define DROP
#ifdef ONLINE
#undef LOCAL
#endif
#ifndef LOCAL
#undef _GLIBCXX_DEBUG
#undef _DEBUG
#endif
#include <cassert>
#include <cmath>
#include <cstring>
#include <deque>
#include <fstream>
//#include <ext/pb_ds/assoc_container.hpp>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <tuple>
#include <type_traits>
#include <chrono>
#include <random>
#include <complex>
#include <bitset>
#include <set>
#include <list>
#include <array>
//#include "compiler_hint.cpp"
template <class T, int S>
struct MDVecDef {
using Type = std::vector<typename MDVecDef<T, S - 1>::Type>;
template <typename... Args>
static Type Make(int n, Args... args) {
return Type(n, MDVecDef<T, S - 1>::Make(args...));
}
};
template <class T>
struct MDVecDef<T, 0> {
using Type = T;
static Type Make(T val = T()) { return val; }
};
template <class T, int S = 1>
using MDVec = typename MDVecDef<T, S>::Type;
#ifndef M_PI
#define M_PI 3.14159265358979323851280895940618620443274267017841L
#endif
#ifndef M_E
#define M_E 2.718281828459045235428168107993940338928950950503355L
#endif
#ifdef LOCAL
#define Assert(x) assert(x)
#define DebugRun(X) X
#define DebugPoint int _x_ = 0; _x_++;
#else
#define Debug(...) 42
#define DebugFmtln(...) 42
#define Assert(x) 42
#define DebugRun(X)
#define DebugPoint
#endif
#define Trace(x) DebugFmtln("Line %d: %s", __LINE__, #x)
template<class T>
inline T DebugRet(T x) {
Debug(x);
return x;
}
#define const_ref(T) const T &
#define mut_ref(T) T &
#define let auto
#define var auto
#define MEMSET0(X) std::memset(&X, 0, sizeof(X))
#define Size(T) int((T).size())
#define All(data) data.begin(), data.end()
#define MakeUnique(data) data.resize(std::unique(All(data)) - data.begin())
#define MakeUniqueAndSort(data) Sort(All(data)); MakeUnique(data)
#define MakeAttribute(struct_name, Type, attr_name) \
struct struct_name { \
using attr_name ## _type = Type; \
Type attr_name; \
mut_ref(Type) get_##attr_name() { return attr_name; } \
const_ref(Type) get_##attr_name() const { return attr_name; } \
};
#define MakeTemplateAttribute(struct_name, attr_name) \
template <class T> \
struct struct_name { \
using attr_name##_type = T; \
T attr_name; \
mut_ref(T) get_##attr_name() { return attr_name; } \
const_ref(T) get_##attr_name() const { return attr_name; } \
};
#define ImplDefaultEq(name) \
bool operator==(const name &a, const name &b) { \
return std::memcmp(&a, &b, sizeof(name)) == 0; \
} \
bool operator!=(const name &a, const name &b) { return !(a == b); }
#define ImplDefaultComparision(name) \
bool operator>(const name &rhs) const { return rhs < *this; } \
bool operator<=(const name &rhs) const { return !(*this > rhs); } \
bool operator>=(const name &rhs) const { return !(*this < rhs); }
#define ImplArithmeticAssignOperation(name) \
name &operator+=(const name &rhs) { return *this = (*this) + rhs; } \
name &operator-=(const name &rhs) { return *this = (*this) - rhs; } \
name &operator*=(const name &rhs) { return *this = (*this) * rhs; } \
name &operator/=(const name &rhs) { return *this = (*this) / rhs; }
#define IsType(Type, param, ret_type) \
template <typename OnlyWhenArg = param> \
enable_if_t<is_same_v<OnlyWhenArg, param> && is_same_v<OnlyWhenArg, Type>, \
ret_type>
#define IsBool(param, ret_type) \
template <bool OnlyWhenArg = param> \
enable_if_t<OnlyWhenArg == (param) && OnlyWhenArg, ret_type>
#define IsBoolStatic(param, ret_type) \
template <bool OnlyWhenArg = param> \
static enable_if_t<OnlyWhenArg == (param) && OnlyWhenArg, ret_type>
#define MakeAnnotation(name) \
template <class T> \
struct is_##name { \
static const bool value = false; \
}; \
template <class T> \
inline constexpr bool is_##name##_v = is_##name<T>::value;
#define AssignAnnotation(cls, annotation) \
template <> \
struct is_##annotation<cls> { \
static const bool value = true; \
};
#define AssignAnnotationTemplate(cls, annotation, type) \
template <type T> \
struct is_##annotation<cls<T>> { \
static const bool value = true; \
};
#define FunctionAlias(from, to) \
template <typename... Args> \
inline auto to(Args &&...args) \
->decltype(from(std::forward<Args>(args)...)) { \
return from(std::forward<Args>(args)...); \
}
#define CastToScalar(field, type) \
operator type() const { return type(field); }
#define CastToAllScalar(field) \
CastToScalar(field, i8); \
CastToScalar(field, u8); \
CastToScalar(field, i16); \
CastToScalar(field, u16); \
CastToScalar(field, i32); \
CastToScalar(field, u32); \
CastToScalar(field, i64); \
CastToScalar(field, u64); \
CastToScalar(field, f32); \
CastToScalar(field, f64); \
CastToScalar(field, f80);
#define COMMA ,
#ifndef LOCAL
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
#else
std::mt19937 rng(0);
#endif
template <class T> T random_choice(T l, T r, std::mt19937 &gen = rng) {
std::uniform_int_distribution<T> random(l, r);
return random(gen);
}
namespace dalt {
#ifndef LOCAL
struct Timer {explicit Timer(const char* m) {}void stop() const {}};
#else
#endif
}
using i8 = char;
using i16 = short;
using i32 = int;
using i64 = long long;
using u8 = unsigned char;
using u16 = unsigned short;
using u32 = unsigned int;
using u64 = unsigned long long;
using usize = size_t;
using f32 = float;
using f64 = double;
// 16 exp, 64 precision
using f80 = long double;
FunctionAlias(std::lower_bound, LowerBound);
FunctionAlias(std::upper_bound, UpperBound);
FunctionAlias(std::unique, Unique);
FunctionAlias(std::swap, Swap);
FunctionAlias(std::min, Min);
FunctionAlias(std::max, Max);
FunctionAlias(std::abs, Abs);
FunctionAlias(std::sin, Sin);
FunctionAlias(std::asin, Asin);
FunctionAlias(std::cos, Cos);
FunctionAlias(std::acos, Acos);
FunctionAlias(std::tan, Tan);
FunctionAlias(std::atan, Atan);
FunctionAlias(std::sort, Sort);
FunctionAlias(std::fill, Fill);
FunctionAlias(std::move, Move);
FunctionAlias(std::reverse, Reverse);
FunctionAlias(std::max_element, MaxElement);
FunctionAlias(std::min_element, MinElement);
FunctionAlias(std::make_tuple, MakeTuple);
FunctionAlias(std::make_pair, MakePair);
FunctionAlias(std::clamp, Clamp);
FunctionAlias(std::shuffle, Shuffle);
FunctionAlias(std::to_string, ToString);
FunctionAlias(std::tie, Tie);
FunctionAlias(std::get<0>, Get0);
FunctionAlias(std::get<1>, Get1);
FunctionAlias(std::get<2>, Get2);
FunctionAlias(std::get<3>, Get3);
FunctionAlias(std::get<4>, Get4);
template <typename _Signature>
using Function = std::function<_Signature>;
template <typename _Signature>
using Func = Function<_Signature>;
using Str = std::string;
using String = Str;
using StringStream = std::stringstream;
using IStream = std::istream;
using OStream = std::ostream;
using std::enable_if;
using std::enable_if_t;
using std::is_base_of;
using std::is_base_of_v;
using std::is_floating_point;
using std::is_floating_point_v;
using std::is_integral;
using std::is_integral_v;
using std::is_arithmetic;
using std::is_arithmetic_v;
using std::is_same;
using std::is_same_v;
using std::tie;
auto &Stderr = std::cerr;
auto &Stdin = std::cin;
auto &Stdout = std::cout;
template <class T>
using Less = std::less<T>;
template <class T>
using Greater = std::greater<T>;
template <typename _Key, typename _Tp, typename _Compare = Less<_Key>>
using TreeMap = std::map<_Key, _Tp, _Compare>;
template <typename _Key, typename _Compare = Less<_Key>>
using TreeSet = std::set<_Key, _Compare>;
template <typename _Key, typename _Compare = std::less<_Key>,
typename _Alloc = std::allocator<_Key>>
using MultiTreeSet = std::multiset<_Key, _Compare, _Alloc>;
template <class T>
using Deque = std::deque<T>;
template <class T>
using Queue = std::queue<T>;
template <class T>
using Vec = std::vector<T>;
template <class T>
using Reducer = Func<T(const T &, const T &)>;
template <class T>
using Comparator = Func<bool(const T &, const T &)>;
template <class T>
using Indexer = Func<T(i32)>;
template <class T>
using Indexer2 = Func<T(i32, i32)>;
template <class A, class B = A, class C = A>
using Adder = Func<C(const A &, const B &)>;
template <class I>
using Checker = Func<bool(const I &)>;
template <class A, class B>
using BiChecker = Func<bool(const A &, const B &)>;
template <class T>
using Consumer = Func<void(const T &)>;
template<class T>
using Supplier = Func<T()>;
template <class FIRST, class SECOND>
using BiConsumer = Func<void(const FIRST &, const SECOND &)>;
template <class F, class T = F>
using Mapper = Func<T(const F &)>;
template <class T>
using MinHeap = std::priority_queue<T, Vec<T>, Greater<T>>;
template <class T>
using MaxHeap = std::priority_queue<T, Vec<T>, Less<T>>;
template <class T, usize S>
using Array = std::array<T, S>;
template <typename... _Elements>
using Tuple = std::tuple<_Elements...>;
template <class T, class = enable_if_t<is_floating_point_v<T>>>
using Complex = std::complex<T>;
template <class A, class B>
using Pair = std::pair<A, B>;
namespace dalt {
template <class T>
IStream& operator>>(IStream& is, Vec<T>& val) {
for (auto& v : val) {
is >> v;
}
return is;
}
#define VEC_OP(op) \
template <class T> \
Vec<T>& operator op(Vec<T>& data, T x) { \
for (auto& v : data) { \
v op x; \
} \
return data; \
}
VEC_OP(+=)
VEC_OP(-=)
VEC_OP(*=)
VEC_OP(/=)
VEC_OP(%=)
VEC_OP(^=)
VEC_OP(&=)
VEC_OP(|=)
VEC_OP(==)
VEC_OP(!=)
template <class T>
int Compare(const Vec<T>& lhs, const Vec<T>& rhs) {
for(int i = 0; i < Size(lhs) && i < Size(rhs); i++) {
if(lhs[i] != rhs[i]) {
return lhs[i] < rhs[i] ? -1 : 1;
}
}
return Size(lhs) < Size(rhs) ? -1 : Size(lhs) > Size(rhs) ? 1 : 0;
}
template <class T>
bool operator<(const Vec<T>& lhs, const Vec<T>& rhs) {
return Compare(lhs, rhs) < 0;
}
template <class T>
bool operator>(const Vec<T>& lhs, const Vec<T>& rhs) {
return Compare(lhs, rhs) > 0;
}
template <class T>
bool operator<=(const Vec<T>& lhs, const Vec<T>& rhs) {
return Compare(lhs, rhs) <= 0;
}
template <class T>
bool operator>=(const Vec<T>& lhs, const Vec<T>& rhs) {
return Compare(lhs, rhs) >= 0;
}
} // namespace dalt
//#include "array_adder.cpp"
using namespace dalt;
namespace dalt {
template <class T>
struct Optional {
using Self = Optional<T>;
private:
T val;
bool show_up;
public:
Optional(const T &arg_val) : val(arg_val), show_up(true) {}
Optional(const T &&arg_val) : val(arg_val), show_up(true) {}
Optional() : show_up(false) {}
const T &value() const {
Assert(show_up);
return val;
}
T &value() {
Assert(show_up);
return val;
}
T &operator*() { return value(); }
const T &operator*() const { return value(); }
bool is_some() const { return show_up; }
bool is_none() const { return !show_up; }
const T *operator->() const {
return &value();
}
T *operator->() { return &value(); }
inline operator T() const { return value(); }
T or_else(T def) const {
if (is_some()) {
return val;
} else {
return def;
}
}
template <class E>
Optional<E> map(const Mapper<T, E> &mapper) const {
if (is_some()) {
return mapper(value());
} else {
return Optional<E>();
}
}
bool operator==(const Self &b) const {
return show_up == b.show_up && (!show_up || val == b.val);
}
};
template <class E>
bool operator!=(const Optional<E> &a, const Optional<E> &b) {
return !(a == b);
}
template <class E>
OStream &operator<<(OStream &os, const Optional<E> &v) {
if (v.is_none()) {
os << "{}";
} else {
os << '{' << v.value() << '}';
}
return os;
}
} // namespace dalt
namespace dalt {
template <class T>
inline enable_if_t<is_integral_v<T>, T> Gcd(T a, T b) {
while (b != 0) {
a %= b;
Swap(a, b);
}
return a;
}
// ret_value = [x, y, gcd(a,b)] that x * a + y * b = gcd(a, b)
template <class T>
inline enable_if_t<is_integral_v<T>, Array<T, 3>> ExtGcd(T a, T b) {
if (b == 0) {
return Array<T, 3>{1, 0, a};
}
auto div = a / b;
auto ans = ExtGcd(b, a - b * div);
auto x = ans[0];
auto y = ans[1];
return Array<T, 3>{y, x - a / b * y, ans[2]};
}
template <class T>
inline enable_if_t<is_integral_v<T>, Optional<T>> PossibleModInverse(
T a, T modulus) {
auto res = ExtGcd(a, modulus);
if (res[2] == 1) {
auto ans = res[0] % modulus;
if (ans < 0) {
ans += modulus;
}
return ans;
}
return {};
}
} // namespace dalt
namespace dalt {
template <class T, class E>
T Modular(E val, T mod) {
val = val % mod;
if (val < 0) {
val = val + mod;
}
return T(val);
}
template<class T>
inline T MulMod(T a, T b, T modulus) {
i64 res = i64(a) * i64(b) % modulus;
return T(res);
}
template<>
inline i64 MulMod<i64>(i64 a, i64 b, i64 modulus) {
#ifdef __SIZEOF_INT128__
// do some fancy stuff here
return __int128_t(a) * __int128_t(b) % modulus;
#else
// do some fallback stuff here
i64 k = roundl((f80)a / modulus * b);
i64 res = (a * b - k * modulus) % modulus;
if (res < 0) {
res += modulus;
}
return res;
#endif
}
template <class T>
inline enable_if_t<is_integral_v<T>, T> AddMod(T a, T b, T modulus) {
T res = a + b;
if (res >= modulus) {
res -= modulus;
}
return res;
}
template <class T, class E>
inline enable_if_t<is_integral_v<T> && is_integral_v<E>, T> PowMod(T x, E exp,
T modulus) {
Assert(exp >= E(0));
if (exp == E(0)) {
return modulus == T(1) ? T(0) : T(1);
}
T ans = PowMod(x, exp >> 1, modulus);
ans = MulMod(ans, ans, modulus);
if (exp & T(1)) {
ans = MulMod(ans, x, modulus);
}
return ans;
}
template <class T>
inline enable_if_t<is_integral_v<T>, T> SubMod(T a, T b, T modulus) {
T res = a - b;
if (res < T(0)) {
res += modulus;
}
return res;
}
} // namespace dalt
namespace dalt {
template <class A, class B>
inline A& Chmin(A& a, const B& b) {
if (a > b) {
a = b;
}
return a;
}
template <class T>
inline T& Chmin(T& a, const T& b, const Comparator<T> &comp) {
if (comp(b, a)) {
a = b;
}
return a;
}
template <class A, class B>
inline A& Chmax(A& a, const B& b) {
if (a < b) {
a = b;
}
return a;
}
template <class T>
inline T& Chmax(T& a, const T& b, const Comparator<T>& comp) {
if (comp(a, b)) {
a = b;
}
return a;
}
template <class T>
inline T& AddTo(T& a, const T& b) {
a = a + b;
return a;
}
template <class T>
inline T& MulTo(T& a, const T& b) {
a = a * b;
return a;
}
template <class T>
inline T& SubFrom(T& a, const T& b) {
a = a - b;
return a;
}
template <class T>
inline T& DivFrom(T& a, const T& b) {
a = a / b;
return a;
}
template <class T, class E>
constexpr enable_if_t<is_integral_v<E>, T> PowBinaryLift(T x, E n) {
if (n == E(0)) {
return T(1);
}
auto ans = PowBinaryLift(x, n >> 1);
ans = ans * ans;
if (n & 1) {
ans = ans * x;
}
return ans;
}
template <class T>
inline T MulLimit(T a, T b, T max, T def) {
if (a == T(0) || b == T(0)) {
return T(0);
}
// a * b <= max
// a <= max / b
// a <= floor(max / b)
if (a <= max / b) {
return a * b;
} else {
return def;
}
}
template <class T>
inline T MulLimit(T a, T b, T max) {
return MulLimit(a, b, max, max);
}
template <class T>
inline T AddLimit(T a, T b, T max, T def) {
if (a <= max - b) {
return a + b;
} else {
return def;
}
}
template <class T>
inline T AddLimit(T a, T b, T max) {
return AddLimit(a, b, max, max);
}
i64 Round(f32 x) { return roundf(x); }
i64 Round(f64 x) { return round(x); }
i64 Round(f80 x) { return roundl(x); }
//l + ... + r
template<class T>
T SumOfInterval(T l, T r) {
if(l > r) {
return T(0);
}
return (l + r) * (r - l + 1) / T(2);
}
template<class T>
T Pow2(T x) {
return x * x;
}
} // namespace dalt
namespace dalt {
// using Type = T;
// static T modulus;
// static T primitive_root;
MakeAnnotation(modular);
template <class T, i64 M, i64 PR = -1, i64 PHI = M - 1>
struct StaticModular {
static_assert(T(M + M) >= 0);
static_assert(is_integral_v<T>);
const static T modulus = M;
const static T primitive_root = PR;
const static T phi = PHI;
using Type = T;
};
template <class T, i64 M, i64 PR, i64 PHI>
struct is_modular<StaticModular<T, M, PR, PHI>> {
static const bool value = true;
};
using MOD998244353 = StaticModular<i32, 998244353, 3>;
using MOD1004535809 = StaticModular<i32, 1004535809, 3>;
using MOD1000000007 = StaticModular<i32, 1000000007, 5>;
using MOD1000000009 = StaticModular<i32, 1000000009, 13>;
using MOD_BIG = StaticModular<i64, 2305843009213693951, -1>;
// last used: -2
template <class T = i32, i64 CID = 0, i64 ID = 0>
struct DynamicModular {
static_assert(is_integral_v<T>);
static T modulus;
static T primitive_root;
static T phi;
static void Register(T _modulus, T _primitive_root = T(), T _phi = T()) {
modulus = _modulus;
primitive_root = _primitive_root;
phi = _phi;
}
using Type = T;
};
template <class T, i64 CID, i64 ID>
T DynamicModular<T, CID, ID>::modulus = T();
template <class T, i64 CID, i64 ID>
T DynamicModular<T, CID, ID>::primitive_root = T();
template <class T, i64 CID, i64 ID>
T DynamicModular<T, CID, ID>::phi = T();
template <class T, i64 CID, i64 ID>
struct is_modular<DynamicModular<T, CID, ID>> {
static const bool value = true;
};
MakeAnnotation(modint);
MakeAnnotation(modint_32);
#define MOD MODULAR::modulus
#define SELF ModInt<MODULAR>
#define TEMPLATE_ARGS template <class MODULAR>
TEMPLATE_ARGS struct ModInt {
using Modular = MODULAR;
using Type = typename MODULAR::Type;
static_assert(is_modular_v<MODULAR>);
static_assert(is_integral_v<Type>);
Type value;
using Self = SELF;
ModInt() : value(0) {}
ModInt(const Type &v) {
value = v;
if (value < 0 || value >= MOD) {
value %= MOD;
if (value < 0) {
value += MOD;
}
}
Assert(value >= 0);
}
static Self nil() {
Self res;
res.value = -1;
return res;
}
bool is_nil() {
return value == -1;
}
explicit operator Type() const { return value; }
static Type modulus() { return MOD; }
static Type primitive_root() { return Modular::primitive_root; }
Self operator-() const { return Self(0) - *this; }
template <class F>
static enable_if_t<is_integral_v<F>, Self> of(F v) {
v %= MOD;
if (v < 0) {
v += MOD;
}
return Self(v);
}
Optional<Self> possible_inv() const {
auto raw_optional_inv = PossibleModInverse(value, MOD);
if (raw_optional_inv.is_some()) {
return Self(raw_optional_inv.value());
} else {
return {};
}
}
Self operator+(const Self &rhs) const {
auto res = value + rhs.value;
if (res >= MOD) {
res -= MOD;
}
return res;
}
Self operator-(const Self &rhs) const {
auto res = value - rhs.value;
if (res < Type(0)) {
res += MOD;
}
return res;
}
Self operator/(const SELF &rhs) const {
auto inv = Self(rhs.possible_inv().value());
return (*this) * inv;
}
bool operator==(const Self &b) const { return value == b.value; }
bool operator!=(const Self &b) const { return value != b.value; }
bool operator<(const Self &b) const { return value < b.value; }
ImplDefaultComparision(Self);
ImplArithmeticAssignOperation(Self);
template <class E>
enable_if_t<is_integral_v<E>, Self> pow(E n) {
return PowBinaryLift(*this, n);
}
friend inline IStream &operator>>(IStream &is, Self &x) {
Type val;
is >> val;
x = Self::of(val);
return is;
}
friend inline OStream &operator<<(OStream &os, const Self &x) {
os << x.value;
return os;
}
};
TEMPLATE_ARGS inline enable_if_t<!is_same_v<MODULAR, MOD_BIG>, SELF> operator*(
const SELF &a, const SELF &b) {
return SELF(MulMod(a.value, b.value, MOD));
}
TEMPLATE_ARGS inline enable_if_t<is_same_v<MODULAR, MOD_BIG>, SELF> operator*(
const SELF &x, const SELF &y) {
static u64 mask = (u64(1) << 32) - 1;
static u64 mod = MOD_BIG::modulus;
u64 a = x.value;
u64 b = y.value;
u64 l1 = a & mask;
u64 h1 = (a >> 32) & mask;
u64 l2 = b & mask;
u64 h2 = (b >> 32) & mask;
u64 l = l1 * l2;
u64 m = l1 * h2 + l2 * h1;
u64 h = h1 * h2;
u64 ret = (l & mod) + (l >> 61) + (h << 3) + (m >> 29) + ((m << 35) >> 3) + 1;
ret = (ret & mod) + (ret >> 61);
ret = (ret & mod) + (ret >> 61);
return SELF(ret - 1);
}
TEMPLATE_ARGS struct is_modint<ModInt<MODULAR>> {
static const bool value = true;
};
TEMPLATE_ARGS struct is_modint_32<ModInt<MODULAR>> {
static const bool value = is_same_v<typename MODULAR::Type, i32>;
};
#undef TEMPLATE_TYPE
#undef MOD
using ModInt998244353 = ModInt<MOD998244353>;
using ModInt1000000007 = ModInt<MOD1000000007>;
using ModInt1000000009 = ModInt<MOD1000000009>;
using ModInt1004535809 = ModInt<MOD1004535809>;
} // namespace dalt
using namespace std;
template <uint32_t mod>
struct LazyMontgomeryModInt {
using mint = LazyMontgomeryModInt;
using i32 = int32_t;
using u32 = uint32_t;
using u64 = uint64_t;
static constexpr u32 get_r() {
u32 ret = mod;
for (i32 i = 0; i < 4; ++i) ret *= 2 - mod * ret;
return ret;
}
static constexpr u32 r = get_r();
static constexpr u32 n2 = -u64(mod) % mod;
static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30");
static_assert((mod & 1) == 1, "invalid, mod % 2 == 0");
static_assert(r * mod == 1, "this code has bugs.");
u32 a;
constexpr LazyMontgomeryModInt() : a(0) {}
constexpr LazyMontgomeryModInt(const int64_t &b)
: a(reduce(u64(b % mod + mod) * n2)){};
static constexpr u32 reduce(const u64 &b) {
return (b + u64(u32(b) * u32(-r)) * mod) >> 32;
}
constexpr mint &operator+=(const mint &b) {
if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod;
return *this;
}
constexpr mint &operator-=(const mint &b) {
if (i32(a -= b.a) < 0) a += 2 * mod;
return *this;
}
constexpr mint &operator*=(const mint &b) {
a = reduce(u64(a) * b.a);
return *this;
}
constexpr mint &operator/=(const mint &b) {
*this *= b.inverse();
return *this;
}
constexpr mint operator+(const mint &b) const { return mint(*this) += b; }
constexpr mint operator-(const mint &b) const { return mint(*this) -= b; }
constexpr mint operator*(const mint &b) const { return mint(*this) *= b; }
constexpr mint operator/(const mint &b) const { return mint(*this) /= b; }
constexpr bool operator==(const mint &b) const {
return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a);
}
constexpr bool operator!=(const mint &b) const {
return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a);
}
constexpr mint operator-() const { return mint() - mint(*this); }
constexpr mint operator+() const { return mint(*this); }
constexpr mint pow(u64 n) const {
mint ret(1), mul(*this);
while (n > 0) {
if (n & 1) ret *= mul;
mul *= mul;
n >>= 1;
}
return ret;
}
constexpr mint inverse() const {
int x = get(), y = mod, u = 1, v = 0, t = 0, tmp = 0;
while (y > 0) {
t = x / y;
x -= t * y, u -= t * v;
tmp = x, x = y, y = tmp;
tmp = u, u = v, v = tmp;
}
return mint{u};
}
friend ostream &operator<<(ostream &os, const mint &b) {
return os << b.get();
}
friend istream &operator>>(istream &is, mint &b) {
int64_t t;
is >> t;
b = LazyMontgomeryModInt<mod>(t);
return (is);
}
constexpr u32 get() const {
u32 ret = reduce(a);
return ret >= mod ? ret - mod : ret;
}
static constexpr u32 get_mod() { return mod; }
};
using MOD = StaticModular<i64, 1234567891>;
using Mi = ModInt<MOD>;
//using Mi = LazyMontgomeryModInt<1234567891>;
void SolveOne(int test_id, IStream &in, OStream &out) {
i32 N;
i64 M;
in >> N >> M;
Vec<int> A(N);
in >> A;
int sum = 0;
for(var a : A) {
sum += a;
}
Debug(N);
Debug(M);
Debug(A);
var create_dp = [&]() {
return MDVecDef<Mi, 1>::Make(2 * sum + 1, Mi(0));
};
var dp = create_dp();
var print_dp = [&]() {
DebugRun({
for(int i = 0; i < Size(dp); i++) {
DebugFmtln("dp[%d] = %d", i, dp[i]);
}
})
};
dp[0] = 1;
//Debug(dp);
for(int bit = 0; (i64(1) << bit) <= M; bit++) {
//Debug(bit);
for(var a : A) {
var next = create_dp();
for(int i = 0; i < Size(next); i++) {
if(i + a < Size(next)) {
next[i + a] += dp[i];
}
next[i] += dp[i];
}
dp = Move(next);
// Debug(a);
// Debug(dp);
}
//compact
int current_bit = (M >> bit) & 1;
var next = create_dp();
for(int i = current_bit; i < Size(dp); i += 2) {
next[i / 2] = dp[i];
}
dp = Move(next);
//Debug(dp);
}
var ans = dp[0];
out << ans;
}
void SolveMulti(IStream &in, OStream &out) {
//std::ifstream input("in");
int num_of_input = 1;
//in >> num_of_input;
for (int i = 0; i < num_of_input; i++) {
//SolveOne(i + 1, input, out);
SolveOne(i + 1, in, out);
}
}
int main() {
std::ios_base::sync_with_stdio(false);
Stdin.tie(0);
Stdout << std::setiosflags(std::ios::fixed);
Stdout << std::setprecision(15);
#ifdef STRESS
stress::Stress();
#else
SolveMulti(Stdin, Stdout);
#endif
return 0;
}