Problem:
Score : 100 points

Problem Statement

There are N items, numbered 1, 2, \ldots, N.
For each i (1 \leq i \leq N), Item i has a weight of w_i and a value of v_i.

Taro has decided to choose some of the N items and carry them home in a knapsack.
The capacity of the knapsack is W, which means that the sum of the weights of items taken must be at most W.

Find the maximum possible sum of the values of items that Taro takes home.

Constraints

All values in input are integers.

1 \leq N \leq 100

1 \leq W \leq 10^9

1 \leq w_i \leq W

1 \leq v_i \leq 10^3

Input

Input is given from Standard Input in the following format:

N W
w_1 v_1
w_2 v_2
:
w_N v_N

Output

Print the maximum possible sum of the values of items that Taro takes home.

Sample Input 1

3 8
3 30
4 50
5 60

Sample Output 1

90

Items 1 and 3 should be taken.
Then, the sum of the weights is 3 + 5 = 8, and the sum of the values is 30 + 60 = 90.

Sample Input 2

1 1000000000
1000000000 10

Sample Output 2

10

Sample Input 3

6 15
6 5
5 6
6 4
6 6
3 5
7 2

Sample Output 3

17

Items 2, 4 and 5 should be taken.
Then, the sum of the weights is 5 + 6 + 3 = 14, and the sum of the values is 6 + 6 + 5 = 17.

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

/**
 * 
 */

// header {{{
#include <bits/stdc++.h>
using namespace std;

using i8   = int8_t;
using u8   = uint8_t;
using i16  = int16_t;
using u16  = uint16_t;
using i32  = int32_t;
using u32  = uint32_t;
using i64  = int64_t;
using u64  = uint64_t;
#ifdef __SIZEOF_INT128__
using i128 = __int128;
using u128 = unsigned __int128;
#endif

using f32  = float;
using f64  = double;
using f80  = __float80;
using f128 = __float128;
// }}}

template<typename T> constexpr T PROCON_INF();
template<> constexpr i64 PROCON_INF<i64>() { return 1'010'000'000'000'000'017LL; }
template<> constexpr f64 PROCON_INF<f64>() { return 1e100; }

constexpr i64 INF  = PROCON_INF<i64>();
constexpr f64 FINF = PROCON_INF<f64>();

constexpr i64 MOD = 1'000'000'007LL;

constexpr f64 EPS = 1e-12;

constexpr f64 PI = 3.14159265358979323846;

// util {{{
#define FOR(i, start, end) for(i64 i = (start), i##_end=(end); i < i##_end; ++i)
#define REP(i, n) FOR(i, 0, n)

#define ALL(f,c,...) (([&](decltype((c)) cccc) { return (f)(std::begin(cccc), std::end(cccc), ## __VA_ARGS__); })(c))
#define SLICE(f,c,l,r,...) (([&](decltype((c)) cccc, decltype((l)) llll, decltype((r)) rrrr) {\
    auto iiii = llll <= rrrr ? std::begin(cccc)+llll : std::end(cccc);\
    auto jjjj = llll <= rrrr ? std::begin(cccc)+rrrr : std::end(cccc);\
    return (f)(iiii, jjjj, ## __VA_ARGS__);\
})(c,l,r))

#define GENERIC(f) ([](auto&&... args) -> decltype(auto) { return (f)(std::forward<decltype(args)>(args)...); })

// BoolArray {{{
class BoolArray {
public:
    using value_type      = bool;
    using reference       = value_type&;
    using const_reference = const value_type&;
    using iterator        = value_type*;
    using const_iterator  = const value_type*;
    using difference_type = ptrdiff_t;
    using size_type       = size_t;

    using reverse_iterator       = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    BoolArray() : BoolArray(0) {}
    explicit BoolArray(size_t n) : BoolArray(n,false) {}
    BoolArray(size_t n, bool value) : size_(n), data_(new bool[n]) {
        ALL(fill, *this, value);
    }

    BoolArray(initializer_list<bool> init) : size_(init.size()), data_(new bool[size_]) {
        ALL(copy, init, begin());
    }

    template<typename InputIt>
    BoolArray(InputIt first, InputIt last) {
        deque<bool> tmp(first, last);
        size_ = tmp.size();
        data_ = new bool[size_];
        ALL(copy, tmp, begin());
    }

    BoolArray(const BoolArray& other) : size_(other.size_), data_(new bool[size_]) {
        ALL(copy, other, begin());
    }

    BoolArray(BoolArray&& other) noexcept : size_(other.size_), data_(other.data_) {
        other.data_ = nullptr;
    }

    BoolArray& operator=(const BoolArray& other) {
        if(this == &other) return *this;
        if(!data_ || size_ < other.size_) {
            delete[] data_;
            data_ = new bool[other.size_];
        }
        size_ = other.size_;
        ALL(copy, other, begin());
        return *this;
    }

    BoolArray& operator=(BoolArray&& other) noexcept {
        if(this == &other) return *this;
        size_ = other.size_;
        data_ = other.data_;
        other.data_ = nullptr;
    }

    BoolArray& operator=(initializer_list<bool> init) {
        if(!data_ || size_ < init.size()) {
            delete[] data_;
            data_ = new bool[init.size()];
        }
        size_ = init.size();
        ALL(copy, init, begin());
        return *this;
    }

    void swap(BoolArray& other) noexcept {
        std::swap(size_, other.size_);
        std::swap(data_, other.data_);
    }

    ~BoolArray() {
        delete[] data_;
        data_ = nullptr;
    }

    bool      empty()    const noexcept { return size_ == 0; }
    size_type size()     const noexcept { return size_; }
    size_type max_size() const noexcept { return 1'010'000'000; }

    iterator       begin()        noexcept { return data_; }
    const_iterator begin()  const noexcept { return data_; }
    const_iterator cbegin() const noexcept { return data_; }

    iterator       end()        noexcept { return data_+size_; }
    const_iterator end()  const noexcept { return data_+size_; }
    const_iterator cend() const noexcept { return data_+size_; }

    reverse_iterator       rbegin()        noexcept { return reverse_iterator(end()); }
    const_reverse_iterator rbegin()  const noexcept { return const_reverse_iterator(end()); }
    const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }

    reverse_iterator       rend()        noexcept { return reverse_iterator(begin()); }
    const_reverse_iterator rend()  const noexcept { return const_reverse_iterator(begin()); }
    const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }

    reference       operator[](size_type pos)       { return data_[pos]; }
    const_reference operator[](size_type pos) const { return data_[pos]; }

    bool*       data()       noexcept { return data_; }
    const bool* data() const noexcept { return data_; }

private:
    size_t size_;
    bool*  data_;
};

void swap(BoolArray& lhs, BoolArray& rhs) noexcept { lhs.swap(rhs); }

bool operator==(const BoolArray& lhs, const BoolArray& rhs) {
    return equal(begin(lhs), end(lhs), begin(rhs), end(rhs));
}
bool operator!=(const BoolArray& lhs, const BoolArray& rhs) { return !(lhs == rhs); }

bool operator<(const BoolArray& lhs, const BoolArray& rhs) {
    return lexicographical_compare(begin(lhs), end(lhs), begin(rhs), end(rhs));
}
bool operator> (const BoolArray& lhs, const BoolArray& rhs) { return rhs < lhs; }
bool operator<=(const BoolArray& lhs, const BoolArray& rhs) { return !(rhs < lhs); }
bool operator>=(const BoolArray& lhs, const BoolArray& rhs) { return !(lhs < rhs); }
// }}}

// 多次元 vector {{{
// 最内周が vector<bool> になるのを避けるための措置
template<typename T>
struct Array1Container {
    using type = vector<T>;
};
template<>
struct Array1Container<bool> {
    using type = BoolArray;
};

// イテレート用
template<typename T>
struct is_arrayn_container {
    static constexpr bool value = false;
};
template<typename T>
struct is_arrayn_container<vector<T>> {
    static constexpr bool value = true;
};
template<>
struct is_arrayn_container<BoolArray> {
    static constexpr bool value = true;
};

template<typename T>
auto arrayn_make(i64 n, T x) {
    using Cont = typename Array1Container<T>::type;
    return Cont(n, x);
}

template<typename T, typename... Args,
         enable_if_t<2 <= sizeof...(Args), nullptr_t> = nullptr>
auto arrayn_make(i64 n, Args... args) {
    auto inner = arrayn_make<T>(args...);
    return vector<decltype(inner)>(n, inner);
}

template<typename T, typename F>
enable_if_t<!is_arrayn_container<T>::value> arrayn_foreach(T& e, F f) {
    f(e);
}

template<typename T, typename F>
enable_if_t<is_arrayn_container<T>::value> arrayn_foreach(T& ary, F f) {
    for(auto& e : ary)
        arrayn_foreach(e, f);
}

template<typename T, typename U>
enable_if_t<is_arrayn_container<T>::value> arrayn_fill(T& ary, const U& x) {
    arrayn_foreach(ary, [&x](auto& e) { e = x; });
}
// }}}

// 多次元生配列 {{{
template<typename T, typename F>
enable_if_t<rank<T>::value==0> CARRAY_FOREACH(T& e, F f) {
    f(e);
}

template<typename Array, typename F>
enable_if_t<rank<Array>::value!=0> CARRAY_FOREACH(Array& ary, F f) {
    for(auto& e : ary)
        CARRAY_FOREACH(e, f);
}

template<typename Array, typename U>
enable_if_t<rank<Array>::value!=0> CARRAY_FILL(Array& ary, const U& v) {
    CARRAY_FOREACH(ary, [&v](auto& e) { e = v; });
}
// }}}

// メモ化ラッパー (8引数まで) {{{
template<i64 N1, typename F>
class Memoized1 {
    static_assert(N1 >= 1, "");
public:
    explicit Memoized1(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1) const {
        using R = decltype(f_(*this,x1));
        static bool done[N1] {};
        static R    memo[N1];
        if(!done[x1]) {
            memo[x1] = f_(*this,x1);
            done[x1] = true;
        }
        return memo[x1];
    }
private:
    const F f_;
};

template<i64 N1, i64 N2, typename F>
class Memoized2 {
    static_assert(N1 >= 1 && N2 >= 1, "");
public:
    explicit Memoized2(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1, i64 x2) const {
        using R = decltype(f_(*this,x1,x2));
        static bool done[N1][N2] {};
        static R    memo[N1][N2];
        if(!done[x1][x2]) {
            memo[x1][x2] = f_(*this,x1,x2);
            done[x1][x2] = true;
        }
        return memo[x1][x2];
    }
private:
    const F f_;
};

template<i64 N1, i64 N2, i64 N3, typename F>
class Memoized3 {
    static_assert(N1 >= 1 && N2 >= 1 && N3 >= 1, "");
public:
    explicit Memoized3(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1, i64 x2, i64 x3) const {
        using R = decltype(f_(*this,x1,x2,x3));
        static bool done[N1][N2][N3] {};
        static R    memo[N1][N2][N3];
        if(!done[x1][x2][x3]) {
            memo[x1][x2][x3] = f_(*this,x1,x2,x3);
            done[x1][x2][x3] = true;
        }
        return memo[x1][x2][x3];
    }
private:
    const F f_;
};

template<i64 N1, i64 N2, i64 N3, i64 N4, typename F>
class Memoized4 {
    static_assert(N1 >= 1 && N2 >= 1 && N3 >= 1 && N4 >= 1, "");
public:
    explicit Memoized4(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1, i64 x2, i64 x3, i64 x4) const {
        using R = decltype(f_(*this,x1,x2,x3,x4));
        static bool done[N1][N2][N3][N4] {};
        static R    memo[N1][N2][N3][N4];
        if(!done[x1][x2][x3][x4]) {
            memo[x1][x2][x3][x4] = f_(*this,x1,x2,x3,x4);
            done[x1][x2][x3][x4] = true;
        }
        return memo[x1][x2][x3][x4];
    }
private:
    const F f_;
};

template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, typename F>
class Memoized5 {
    static_assert(N1 >= 1 && N2 >= 1 && N3 >= 1 && N4 >= 1 && N5 >= 1, "");
public:
    explicit Memoized5(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1, i64 x2, i64 x3, i64 x4, i64 x5) const {
        using R = decltype(f_(*this,x1,x2,x3,x4,x5));
        static bool done[N1][N2][N3][N4][N5] {};
        static R    memo[N1][N2][N3][N4][N5];
        if(!done[x1][x2][x3][x4][x5]) {
            memo[x1][x2][x3][x4][x5] = f_(*this,x1,x2,x3,x4,x5);
            done[x1][x2][x3][x4][x5] = true;
        }
        return memo[x1][x2][x3][x4][x5];
    }
private:
    const F f_;
};

template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, i64 N6, typename F>
class Memoized6 {
    static_assert(N1 >= 1 && N2 >= 1 && N3 >= 1 && N4 >= 1 && N5 >= 1 && N6 >= 1, "");
public:
    explicit Memoized6(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1, i64 x2, i64 x3, i64 x4, i64 x5, i64 x6) const {
        using R = decltype(f_(*this,x1,x2,x3,x4,x5,x6));
        static bool done[N1][N2][N3][N4][N5][N6] {};
        static R    memo[N1][N2][N3][N4][N5][N6];
        if(!done[x1][x2][x3][x4][x5][x6]) {
            memo[x1][x2][x3][x4][x5][x6] = f_(*this,x1,x2,x3,x4,x5,x6);
            done[x1][x2][x3][x4][x5][x6] = true;
        }
        return memo[x1][x2][x3][x4][x5][x6];
    }
private:
    const F f_;
};

template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, i64 N6, i64 N7, typename F>
class Memoized7 {
    static_assert(N1 >= 1 && N2 >= 1 && N3 >= 1 && N4 >= 1 && N5 >= 1 && N6 >= 1 && N7 >= 1, "");
public:
    explicit Memoized7(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1, i64 x2, i64 x3, i64 x4, i64 x5, i64 x6, i64 x7) const {
        using R = decltype(f_(*this,x1,x2,x3,x4,x5,x6,x7));
        static bool done[N1][N2][N3][N4][N5][N6][N7] {};
        static R    memo[N1][N2][N3][N4][N5][N6][N7];
        if(!done[x1][x2][x3][x4][x5][x6][x7]) {
            memo[x1][x2][x3][x4][x5][x6][x7] = f_(*this,x1,x2,x3,x4,x5,x6,x7);
            done[x1][x2][x3][x4][x5][x6][x7] = true;
        }
        return memo[x1][x2][x3][x4][x5][x6][x7];
    }
private:
    const F f_;
};

template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, i64 N6, i64 N7, i64 N8, typename F>
class Memoized8 {
    static_assert(N1 >= 1 && N2 >= 1 && N3 >= 1 && N4 >= 1 && N5 >= 1 && N6 >= 1 && N7 >= 1 && N8 >= 1, "");
public:
    explicit Memoized8(F&& f) : f_(forward<F>(f)) {}
    decltype(auto) operator()(i64 x1, i64 x2, i64 x3, i64 x4, i64 x5, i64 x6, i64 x7, i64 x8) const {
        using R = decltype(f_(*this,x1,x2,x3,x4,x5,x6,x7,x8));
        static bool done[N1][N2][N3][N4][N5][N6][N7][N8] {};
        static R    memo[N1][N2][N3][N4][N5][N6][N7][N8];
        if(!done[x1][x2][x3][x4][x5][x6][x7][x8]) {
            memo[x1][x2][x3][x4][x5][x6][x7][x8] = f_(*this,x1,x2,x3,x4,x5,x6,x7,x8);
            done[x1][x2][x3][x4][x5][x6][x7][x8] = true;
        }
        return memo[x1][x2][x3][x4][x5][x6][x7][x8];
    }
private:
    const F f_;
};

template<i64 N1, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized1<N1,F>(forward<F>(f));
}
template<i64 N1, i64 N2, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized2<N1,N2,F>(forward<F>(f));
}
template<i64 N1, i64 N2, i64 N3, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized3<N1,N2,N3,F>(forward<F>(f));
}
template<i64 N1, i64 N2, i64 N3, i64 N4, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized4<N1,N2,N3,N4,F>(forward<F>(f));
}
template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized5<N1,N2,N3,N4,N5,F>(forward<F>(f));
}
template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, i64 N6, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized6<N1,N2,N3,N4,N5,N6,F>(forward<F>(f));
}
template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, i64 N6, i64 N7, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized7<N1,N2,N3,N4,N5,N6,N7,F>(forward<F>(f));
}
template<i64 N1, i64 N2, i64 N3, i64 N4, i64 N5, i64 N6, i64 N7, i64 N8, typename F>
decltype(auto) MEMOIZE(F&& f) {
    return Memoized8<N1,N2,N3,N4,N5,N6,N7,N8,F>(forward<F>(f));
}

// }}}

// lambda で再帰 {{{
template<typename F>
class FixPoint {
public:
    explicit constexpr FixPoint(F&& f) : f_(forward<F>(f)) {}

    template<typename... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return f_(*this, forward<Args>(args)...);
    }

private:
    const F f_;
};

template<typename F>
decltype(auto) FIX(F&& f) {
    return FixPoint<F>(forward<F>(f));
}
// }}}

// tuple {{{
template<typename... TS,
         enable_if_t<0 < sizeof...(TS), nullptr_t> = nullptr>
constexpr auto tuple_head(const tuple<TS...>& t) {
    return get<0>(t);
}

template<typename... TS, size_t i, size_t... is>
constexpr auto tuple_tail_helper(const tuple<TS...>& t, index_sequence<i,is...>) {
    return make_tuple(get<is>(t)...);
}

template<typename... TS,
         enable_if_t<1 == sizeof...(TS), nullptr_t> = nullptr>
constexpr auto tuple_tail(const tuple<TS...>&) {
    return make_tuple();
}

template<typename... TS,
         enable_if_t<1 < sizeof...(TS), nullptr_t> = nullptr>
constexpr auto tuple_tail(const tuple<TS...>& t) {
    return tuple_tail_helper(t, make_index_sequence<sizeof...(TS)>());
}
// }}}

// FST/SND {{{
template<typename T1, typename T2>
T1& FST(pair<T1,T2>& p) {
    return p.first;
}

template<typename T1, typename T2>
const T1& FST(const pair<T1,T2>& p) {
    return p.first;
}

template<typename T1, typename T2>
T2& SND(pair<T1,T2>& p) {
    return p.second;
}

template<typename T1, typename T2>
const T2& SND(const pair<T1,T2>& p) {
    return p.second;
}

template<typename... TS, enable_if_t<1 <= sizeof...(TS), nullptr_t> = nullptr>
auto& FST(tuple<TS...>& t) {
    return get<0>(t);
}

template<typename... TS, enable_if_t<1 <= sizeof...(TS), nullptr_t> = nullptr>
const auto& FST(const tuple<TS...>& t) {
    return get<0>(t);
}

template<typename... TS, enable_if_t<2 <= sizeof...(TS), nullptr_t> = nullptr>
auto& SND(tuple<TS...>& t) {
    return get<1>(t);
}

template<typename... TS, enable_if_t<2 <= sizeof...(TS), nullptr_t> = nullptr>
const auto& SND(const tuple<TS...>& t) {
    return get<1>(t);
}
// }}}

template<typename T1, typename T2, typename Comp=less<>,
         enable_if_t<is_signed<T1>::value != is_unsigned<T2>::value, nullptr_t> = nullptr>
common_type_t<T1,T2> MAX(T1 x, T2 y, Comp comp={}) {
    return max<common_type_t<T1,T2>>(x, y, comp);
}

template<typename T, typename Comp=less<>>
const T& MAX(const T& x, const T& y, Comp comp={}) {
    return max(x, y, comp);
}

template<typename T, typename Comp=less<>>
T MAX(initializer_list<T> ilist, Comp comp={}) {
    return max(ilist, comp);
}

template<typename T1, typename T2, typename Comp=less<>,
         enable_if_t<is_signed<T1>::value != is_unsigned<T2>::value, nullptr_t> = nullptr>
common_type_t<T1,T2> MIN(T1 x, T2 y, Comp comp={}) {
    return min<common_type_t<T1,T2>>(x, y, comp);
}

template<typename T, typename Comp=less<>>
const T& MIN(const T& x, const T& y, Comp comp={}) {
    return min(x, y, comp);
}

template<typename T, typename Comp=less<>>
T MIN(initializer_list<T> ilist, Comp comp={}) {
    return min(ilist, comp);
}

template<typename C>
i64 SIZE(const C& c) { return static_cast<i64>(c.size()); }

template<typename T, size_t N>
i64 SIZE(const T (&)[N]) { return static_cast<i64>(N); }

bool is_odd (i64 x) { return x % 2 != 0; }
bool is_even(i64 x) { return x % 2 == 0; }

template<typename T> i64 cmp(T x, T y) { return (y<x) - (x<y); }
template<typename T> i64 sgn(T x) { return cmp(x, T(0)); }

// lo:OK, hi:NG
template<typename Pred>
i64 bisect_integer(i64 lo, i64 hi, Pred pred) {
    assert(lo < hi);

    while(lo+1 < hi) {
        i64 mid = (lo+hi) / 2;
        if(pred(mid))
            lo = mid;
        else
            hi = mid;
    }
    return lo;
}

template<typename Pred>
f64 bisect_real(f64 lo, f64 hi, Pred pred, i64 iter=100) {
    assert(lo < hi);

    REP(_, iter) {
        f64 mid = (lo+hi) / 2;
        if(pred(mid))
            lo = mid;
        else
            hi = mid;
    }
    return lo;
}

i64 ipow(i64 x, i64 e) {
    assert(e >= 0);
    i64 res = 1;
    REP(_, e) {
        res *= x;
    }
    return res;
}

i64 isqrt(i64 x) {
    assert(x >= 0);

    i64 lo = 0;
    i64 hi = MIN(x/2+2, 3037000500LL);
    return bisect_integer(lo, hi, [x](i64 r) { return r*r <= x; });
}

// 0 <= ilog2(x) <= 62
i64 ilog2(i64 x) {
    assert(x > 0);
    return 63 - __builtin_clzll(x);
}

// 0 <= ilog10(x) <= 18
i64 ilog10(i64 x) {
    assert(x > 0);
    static constexpr i64 TABLE[18] {
        9LL,
        99LL,
        999LL,
        9999LL,
        99999LL,
        999999LL,
        9999999LL,
        99999999LL,
        999999999LL,
        9999999999LL,
        99999999999LL,
        999999999999LL,
        9999999999999LL,
        99999999999999LL,
        999999999999999LL,
        9999999999999999LL,
        99999999999999999LL,
        999999999999999999LL,
    };
    REP(i, SIZE(TABLE)) {
        if(x <= TABLE[i]) return i;
    }
    return SIZE(TABLE);
}

// Haskell の divMod と同じ
pair<i64,i64> divmod(i64 a, i64 b) {
    i64 q = a / b;
    i64 r = a % b;
    if((b>0 && r<0) || (b<0 && r>0)) {
        --q;
        r += b;
    }
    return {q,r};
}

i64 div_ceil(i64 a, i64 b) {
    i64 q = a / b;
    i64 r = a % b;
    if((b>0 && r>0) || (b<0 && r<0))
        ++q;
    return q;
}

i64 div_floor(i64 a, i64 b) {
    return divmod(a,b).first;
}

i64 modulo(i64 a, i64 b) {
    return divmod(a,b).second;
}

bool feq(f64 x, f64 y, f64 eps=EPS) {
    return fabs(x-y) < eps;
}

template<typename T, typename U, typename Comp=less<>>
bool chmax(T& xmax, const U& x, Comp comp={}) {
    if(comp(xmax, x)) {
        xmax = x;
        return true;
    }
    return false;
}

template<typename T, typename U, typename Comp=less<>>
bool chmin(T& xmin, const U& x, Comp comp={}) {
    if(comp(x, xmin)) {
        xmin = x;
        return true;
    }
    return false;
}

template<typename Pred>
i64 arg_find(i64 lo, i64 hi, Pred pred) {
    assert(lo < hi);

    FOR(x, lo, hi) {
        if(pred(x)) return x;
    }
    return INF;
}

template<typename F>
i64 arg_max(i64 lo, i64 hi, F f) {
    assert(lo < hi);

    i64 res = lo;
    auto ymax = f(lo);
    FOR(x, lo+1, hi) {
        if(chmax(ymax, f(x)))
            res = x;
    }
    return res;
}

template<typename F>
i64 arg_min(i64 lo, i64 hi, F f) {
    assert(lo < hi);

    i64 res = lo;
    auto ymin = f(lo);
    FOR(x, lo+1, hi) {
        if(chmin(ymin, f(x)))
            res = x;
    }
    return res;
}

template<typename Pred>
i64 arg_find_r(i64 lo, i64 hi, Pred pred) {
    i64 x = arg_find(-hi+1, lo+1, [pred](i64 xx) { return pred(-xx); });
    return x == INF ? INF : -x;
}

template<typename F>
i64 arg_max_r(i64 lo, i64 hi, F f) {
    return -arg_max(-hi+1, lo+1, [f](i64 x) { return f(-x); });
}

template<typename F>
i64 arg_min_r(i64 lo, i64 hi, F f) {
    return -arg_min(-hi+1, lo+1, [f](i64 x) { return f(-x); });
}

template<typename ForwardIt, typename T, typename Comp=less<>>
ForwardIt bsearch_find(ForwardIt first, ForwardIt last, const T& x, Comp comp={}) {
    auto it = lower_bound(first, last, x, comp);
    if(it == last || comp(x,*it)) return last;
    return it;
}

// x 未満の最後の要素
template<typename BidiIt, typename T, typename Comp=less<>>
BidiIt bsearch_lt(BidiIt first, BidiIt last, const T& x, Comp comp={}) {
    auto it = lower_bound(first, last, x, comp);
    if(it == first) return last;
    return prev(it);
}

// x 以下の最後の要素
template<typename BidiIt, typename T, typename Comp=less<>>
BidiIt bsearch_le(BidiIt first, BidiIt last, const T& x, Comp comp={}) {
    auto it = upper_bound(first, last, x, comp);
    if(it == first) return last;
    return prev(it);
}

// x より大きい最初の要素
template<typename BidiIt, typename T, typename Comp=less<>>
BidiIt bsearch_gt(BidiIt first, BidiIt last, const T& x, Comp comp={}) {
    return upper_bound(first, last, x, comp);
}

// x 以上の最初の要素
template<typename BidiIt, typename T, typename Comp=less<>>
BidiIt bsearch_ge(BidiIt first, BidiIt last, const T& x, Comp comp={}) {
    return lower_bound(first, last, x, comp);
}

template<typename InputIt>
auto SUM(InputIt first, InputIt last) {
    using T = typename iterator_traits<InputIt>::value_type;
    return accumulate(first, last, T());
}

template<typename ForwardIt, typename UnaryOperation>
ForwardIt transform_self(ForwardIt first, ForwardIt last, UnaryOperation op) {
    return transform(first, last, first, op);
}

template<typename C>
void UNIQ(C& c) {
    c.erase(ALL(unique,c), end(c));
}

template<typename BinaryFunc>
auto FLIP(BinaryFunc f) {
    return [f](const auto& x, const auto& y) {
        return f(y,x);
    };
}

template<typename BinaryFunc, typename UnaryFunc>
auto ON(BinaryFunc bf, UnaryFunc uf) {
    return [bf,uf](const auto& x, const auto& y) {
        return bf(uf(x), uf(y));
    };
}

template<typename F>
auto LT_ON(F f) { return ON(less<>(), f); }

template<typename F>
auto GT_ON(F f) { return ON(greater<>(), f); }

template<typename F>
auto EQ_ON(F f) { return ON(equal_to<>(), f); }

template<typename F>
auto NE_ON(F f) { return ON(not_equal_to<>(), f); }

template<typename Comp=less<>>
auto EQUIV(Comp comp={}) {
    return [comp](const auto& lhs, const auto& rhs) {
        return !comp(lhs,rhs) && !comp(rhs,lhs);
    };
}

struct IDENTITY {
    template<typename T>
    constexpr T&& operator()(T&& x) const noexcept {
        return forward<T>(x);
    }
};

template<typename ForwardIt>
ForwardIt next_bounded(ForwardIt last, ForwardIt it, i64 n=1) {
    auto bound = distance(it, last);
    return next(it, MIN(n, bound));
}

template<typename ForwardIt>
ForwardIt prev_bounded(ForwardIt first, ForwardIt it, i64 n=1) {
    auto bound = distance(first, it);
    return prev(it, MIN(n, bound));
}

template<typename ForwardIt>
void advance_bounded(ForwardIt first, ForwardIt last, ForwardIt& it, i64 n) {
    if(n > 0) {
        auto bound = distance(it, last);
        advance(it, MIN(n, bound));
    }
    else if(n < 0) {
        auto bound = distance(it, first);
        advance(it, MAX(n, bound));
    }
}

char digit_chr(i64 n) {
    return static_cast<char>('0' + n);
}

i64 digit_ord(char c) {
    return c - '0';
}

char lower_chr(i64 n) {
    return static_cast<char>('a' + n);
}

i64 lower_ord(char c) {
    return c - 'a';
}

char upper_chr(i64 n) {
    return static_cast<char>('A' + n);
}

i64 upper_ord(char c) {
    return c - 'A';
}

// 出力は operator<< を直接使わず、このテンプレート経由で行う
// 提出用出力とデバッグ用出力を分けるため
template<typename T>
struct Formatter {
    static ostream& write_str(ostream& out, const T& x)  { return out << x; }
    static ostream& write_repr(ostream& out, const T& x) { return out << x; }
};

template<typename T>
ostream& WRITE_STR(ostream& out, const T& x) {
    return Formatter<T>::write_str(out, x);
}

template<typename T>
ostream& WRITE_REPR(ostream& out, const T& x) {
    return Formatter<T>::write_repr(out, x);
}

template<typename InputIt>
ostream& WRITE_JOIN_STR(ostream& out, InputIt first, InputIt last, const string& sep) {
    while(first != last) {
        WRITE_STR(out, *first++);
        if(first != last)
            out << sep;
    }
    return out;
}

template<typename InputIt>
ostream& WRITE_JOIN_REPR(ostream& out, InputIt first, InputIt last, const string& sep) {
    while(first != last) {
        WRITE_REPR(out, *first++);
        if(first != last)
            out << sep;
    }
    return out;
}

template<typename InputIt>
ostream& WRITE_RANGE_STR(ostream& out, InputIt first, InputIt last) {
    return WRITE_JOIN_STR(out, first, last, " ");
}

template<typename InputIt>
ostream& WRITE_RANGE_REPR(ostream& out, InputIt first, InputIt last) {
    out << "[";
    WRITE_JOIN_REPR(out, first, last, ", ");
    out << "]";
    return out;
}

template<typename T>
void FROM_STR(const string& s, T& x) {
    istringstream in(s);
    in >> x;
}

template<typename T>
string TO_STR(const T& x) {
    ostringstream out;
    WRITE_STR(out, x);
    return out.str();
}

template<typename T>
string TO_REPR(const T& x) {
    ostringstream out;
    WRITE_REPR(out, x);
    return out.str();
}

template<typename InputIt>
string RANGE_TO_STR(InputIt first, InputIt last) {
    ostringstream out;
    WRITE_RANGE_STR(out, first, last);
    return out.str();
}

template<typename InputIt>
string RANGE_TO_REPR(InputIt first, InputIt last) {
    ostringstream out;
    WRITE_RANGE_REPR(out, first, last);
    return out.str();
}

template<typename InputIt>
string JOIN(InputIt first, InputIt last, const string& sep) {
    ostringstream out;
    WRITE_JOIN_STR(out, first, last, sep);
    return out.str();
}

template<>
struct Formatter<i64> {
    static ostream& write_str(ostream& out, i64 x) {
        return out << x;
    }
    static ostream& write_repr(ostream& out, i64 x) {
        if(x == INF) return out << "INF";
        if(x == -INF) return out << "-INF";
        return out << x;
    }
};

template<>
struct Formatter<f64> {
    static ostream& write_str(ostream& out, f64 x) {
        return out << x;
    }
    static ostream& write_repr(ostream& out, f64 x) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
        if(x == FINF) return out << "FINF";
        if(x == -FINF) return out << "-FINF";
#pragma GCC diagnostic pop
        return out << x;
    }
};

template<typename T>
struct Formatter<vector<T>> {
    static ostream& write_str(ostream& out, const vector<T>& v) {
        return WRITE_RANGE_STR(out, begin(v), end(v));
    }
    static ostream& write_repr(ostream& out, const vector<T>& v) {
        out << "vector";
        return WRITE_RANGE_REPR(out, begin(v), end(v));
    }
};

template<>
struct Formatter<BoolArray> {
    static ostream& write_str(ostream& out, const BoolArray& a) {
        return WRITE_RANGE_STR(out, begin(a), end(a));
    }
    static ostream& write_repr(ostream& out, const BoolArray& a) {
        out << "BoolArray";
        return WRITE_RANGE_REPR(out, begin(a), end(a));
    }
};

template<typename T1, typename T2>
struct Formatter<pair<T1,T2>> {
    static ostream& write_str(ostream& out, const pair<T1,T2>& p) {
        WRITE_STR(out, p.first);
        out << ' ';
        WRITE_STR(out, p.second);
        return out;
    }
    static ostream& write_repr(ostream& out, const pair<T1,T2>& p) {
        out << "(";
        WRITE_REPR(out, p.first);
        out << ",";
        WRITE_REPR(out, p.second);
        out << ")";
        return out;
    }
};

template<typename... TS>
struct Formatter<tuple<TS...>> {
    template<size_t I=0, enable_if_t<I == sizeof...(TS), nullptr_t> = nullptr>
    static ostream& write_str_impl(ostream& out, const tuple<TS...>&) {
        return out;
    }
    template<size_t I=0, enable_if_t<I < sizeof...(TS), nullptr_t> = nullptr>
    static ostream& write_str_impl(ostream& out, const tuple<TS...>& t) {
        if(I != 0) out << ' ';
        WRITE_STR(out, get<I>(t));
        return write_str_impl<I+1>(out, t);
    }

    template<size_t I=0, enable_if_t<I == sizeof...(TS), nullptr_t> = nullptr>
    static ostream& write_repr_impl(ostream& out, const tuple<TS...>&) {
        if(sizeof...(TS) == 0) out << "(";
        return out << ")";
    }
    template<size_t I=0, enable_if_t<I < sizeof...(TS), nullptr_t> = nullptr>
    static ostream& write_repr_impl(ostream& out, const tuple<TS...>& t) {
        if(I == 0)
            out << "(";
        else
            out << ",";
        WRITE_REPR(out, get<I>(t));
        return write_repr_impl<I+1>(out, t);
    }

    static ostream& write_str(ostream& out, const tuple<TS...>& t) {
        return write_str_impl(out, t);
    }
    static ostream& write_repr(ostream& out, const tuple<TS...>& t) {
        return write_repr_impl(out, t);
    }
};

template<typename T>
void RD(T& x) {
    cin >> x;
#ifdef PROCON_LOCAL
    assert(cin);
#endif
}

template<typename T>
void RD1(T& x) {
    RD(x);
    --x;
}

template<typename T>
auto RD_ARRAY(i64 n) {
    auto res = arrayn_make<T>(n, T());
    arrayn_foreach(res, [](T& e) { RD(e); });
    return res;
}

template<typename T>
auto RD1_ARRAY(i64 n) {
    auto res = arrayn_make<T>(n, T());
    arrayn_foreach(res, [](T& e) { RD1(e); });
    return res;
}

template<typename T>
auto RD_ARRAY2(i64 h, i64 w) {
    auto res = arrayn_make<T>(h,w, T());
    arrayn_foreach(res, [](T& e) { RD(e); });
    return res;
}

template<typename T>
auto RD1_ARRAY2(i64 h, i64 w) {
    auto res = arrayn_make<T>(h,w, T());
    arrayn_foreach(res, [](T& e) { RD1(e); });
    return res;
}

template<typename T1, typename T2>
pair<T1,T2> RD_PAIR() {
    T1 x; RD(x);
    T2 y; RD(y);
    return { x, y };
}

template<typename T1, typename T2>
pair<T1,T2> RD1_PAIR() {
    T1 x; RD1(x);
    T2 y; RD1(y);
    return { x, y };
}

template<typename... TS,
         enable_if_t<0 == sizeof...(TS), nullptr_t> = nullptr>
auto RD_TUPLE() {
    return make_tuple();
}

template<typename T, typename... TS>
auto RD_TUPLE() {
    T x; RD(x);
    return tuple_cat(make_tuple(x), RD_TUPLE<TS...>());
}

template<typename... TS,
         enable_if_t<0 == sizeof...(TS), nullptr_t> = nullptr>
auto RD1_TUPLE() {
    return make_tuple();
}

template<typename T, typename... TS>
auto RD1_TUPLE() {
    T x; RD1(x);
    return tuple_cat(make_tuple(x), RD_TUPLE<TS...>());
}

void PRINT() {}

template<typename T, typename... TS>
void PRINT(const T& x, const TS& ...args) {
    WRITE_STR(cout, x);
    if(sizeof...(args)) {
        cout << ' ';
        PRINT(args...);
    }
}

template<typename... TS>
void PRINTLN(const TS& ...args) {
    PRINT(args...);
    cout << '\n';
}

[[noreturn]] void EXIT() {
    cout.flush();
#ifdef PROCON_LOCAL
    cerr.flush();
    exit(0);
#else
    _Exit(0);
#endif
}

template<typename... TS, enable_if_t<1 == sizeof...(TS), nullptr_t> = nullptr>
void DBG_IMPL(i64 line, const char* expr, const tuple<TS...>& value) {
#ifdef PROCON_LOCAL
    cerr << "[L " << line << "]: ";
    cerr << expr << " = ";
    WRITE_REPR(cerr, get<0>(value));
    cerr << "\n";
#endif
}

template<typename... TS, enable_if_t<2 <= sizeof...(TS), nullptr_t> = nullptr>
void DBG_IMPL(i64 line, const char* expr, const tuple<TS...>& value) {
#ifdef PROCON_LOCAL
    cerr << "[L " << line << "]: ";
    cerr << "(" << expr << ") = ";
    WRITE_REPR(cerr, value);
    cerr << "\n";
#endif
}

template<typename T, size_t N>
void DBG_CARRAY_IMPL(i64 line, const char* expr, const T (&ary)[N]) {
#ifdef PROCON_LOCAL
    cerr << "[L " << line << "]: ";
    cerr << expr << " = ";
    WRITE_RANGE_REPR(cerr, begin(ary), end(ary));
    cerr << "\n";
#endif
}

template<typename InputIt>
void DBG_RANGE_IMPL(i64 line, const char* expr1, const char* expr2, InputIt first, InputIt last) {
#ifdef PROCON_LOCAL
    cerr << "[L " << line << "]: ";
    cerr << expr1 << "," << expr2 << " = ";
    WRITE_RANGE_REPR(cerr, first, last);
    cerr << "\n";
#endif
}

#define DBG(args...) DBG_IMPL(__LINE__, (#args), make_tuple(args))
#define DBG_CARRAY(expr) DBG_CARRAY_IMPL(__LINE__, #expr, (expr))
#define DBG_RANGE(first,last) DBG_RANGE_IMPL(__LINE__, #first, #last, (first), (last))

#define PAIR  make_pair
#define TUPLE make_tuple
// }}}

// init {{{
struct ProconInit {
    static constexpr int IOS_PREC = 15;
    static constexpr bool AUTOFLUSH = false;

    ProconInit() {
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(IOS_PREC);
#ifdef PROCON_LOCAL
        cerr << fixed << setprecision(IOS_PREC);
#endif
        if(AUTOFLUSH)
            cout << unitbuf;
    }
} PROCON_INIT;
// }}}

// random {{{

// PCGEngine {{{
// PCG random number generator
//
// http://www.pcg-random.org/
// https://github.com/imneme/pcg-c-basic
class PcgEngine {
public:
    using result_type = std::uint32_t;
    static constexpr result_type min() { return std::numeric_limits<result_type>::min(); }
    static constexpr result_type max() { return std::numeric_limits<result_type>::max(); }

    PcgEngine(std::uint64_t seed, std::uint64_t seq) {
        init(seed, seq);
    }

    template<typename SeedSeq>
    explicit PcgEngine(SeedSeq& ss) {
        std::uint32_t xs[4];
        ss.generate(std::begin(xs), std::end(xs));
        std::uint64_t seed = (std::uint64_t(xs[0])<<32) | xs[1];
        std::uint64_t seq  = (std::uint64_t(xs[2])<<32) | xs[3];
        init(seed, seq);
    }

    std::uint32_t operator()() {
        std::uint32_t xorshifted = std::uint32_t(((state_>>18) ^ state_) >> 27);
        std::uint32_t rot = std::uint32_t(state_ >> 59);
        std::uint32_t res = (xorshifted>>rot) | (xorshifted<<((-rot)&31));
        state_ = 6364136223846793005ULL*state_ + inc_;
        return res;
    }

private:
    void init(std::uint64_t seed, std::uint64_t seq) {
        state_ = 0;
        inc_ = (seq<<1) | 1;
        (*this)();
        state_ += seed;
        (*this)();
    }

    std::uint64_t state_;
    std::uint64_t inc_;
};
// }}}

// Seeder {{{
class Seeder {
private:
    static constexpr std::uint32_t INIT_A = 0x43b0d7e5;
    static constexpr std::uint32_t MULT_A = 0x931e8875;

    static constexpr std::uint32_t INIT_B = 0x8b51f9dd;
    static constexpr std::uint32_t MULT_B = 0x58f38ded;

    static constexpr std::uint32_t MIX_MULT_L = 0xca01f9dd;
    static constexpr std::uint32_t MIX_MULT_R = 0x4973f715;
    static constexpr std::uint32_t XSHIFT = 16;

    static constexpr std::uint32_t fast_exp(std::uint32_t x, std::uint32_t e) {
        std::uint32_t res = 1;
        std::uint32_t mul = x;
        while(e > 0) {
            if(e & 1)
                res *= mul;
            mul *= mul;
            e >>= 1;
        }
        return res;
    }

    template<typename InputIt>
    void mix_entropy(InputIt first, InputIt last) {
        std::uint32_t hash_const = INIT_A;
        auto h = [&hash_const](std::uint32_t x) {
            x ^= hash_const;
            hash_const *= MULT_A;
            x *= hash_const;
            x ^= x >> XSHIFT;
            return x;
        };
        auto mix = [](std::uint32_t x, std::uint32_t y) {
            std::uint32_t res = MIX_MULT_L*x - MIX_MULT_R*y;
            res ^= res >> XSHIFT;
            return res;
        };

        InputIt it = first;
        for(auto& elem : mixer_)
            elem = h(it == last ? 0 : *it++);
        for(auto& src : mixer_)
            for(auto& dest : mixer_)
                if(&src != &dest)
                    dest = mix(dest, h(src));
        for(; it != last; ++it)
            for(auto& dest : mixer_)
                dest = mix(dest, h(*it));
    }

    std::uint32_t mixer_[4];

public:
    using result_type = std::uint32_t;

    Seeder(const Seeder&)         = delete;
    void operator=(const Seeder&) = delete;

    template<typename InputIt>
    Seeder(InputIt first, InputIt last) {
        seed(first, last);
    }

    template<typename T>
    Seeder(std::initializer_list<T> ilist) : Seeder(std::begin(ilist),std::end(ilist)) {}

    template<typename InputIt>
    void seed(InputIt first, InputIt last) {
        mix_entropy(first, last);
    }

    template<typename RandomIt>
    void generate(RandomIt dst_first, RandomIt dst_last) const {
        auto src_first = std::begin(mixer_);
        auto src_last  = std::end(mixer_);
        auto src       = src_first;
        std::uint32_t hash_const = INIT_B;
        for(auto dst = dst_first; dst != dst_last; ++dst) {
            std::uint32_t x = *src++;
            if(src == src_last)
                src = src_first;
            x ^= hash_const;
            hash_const *= MULT_B;
            x *= hash_const;
            x ^= x >> XSHIFT;
            *dst = x;
        }
    }

    std::size_t size() const { return 4; }

    template<typename OutputIt>
    void param(OutputIt first) const {
        constexpr std::uint32_t INV_A     = fast_exp(MULT_A,     std::uint32_t(-1));
        constexpr std::uint32_t MIX_INV_L = fast_exp(MIX_MULT_L, std::uint32_t(-1));

        std::uint32_t res[4];
        std::copy(std::begin(mixer_), std::end(mixer_), std::begin(res));

        std::uint32_t hash_const = INIT_A * fast_exp(MULT_A, 16);
        for(auto src = std::rbegin(res); src != std::rend(res); ++src) {
            for(auto dst = std::rbegin(res); dst != std::rend(res); ++dst) {
                if(src == dst) continue;
                std::uint32_t revhashed = *src;
                std::uint32_t mult_const = hash_const;
                hash_const *= INV_A;
                revhashed ^= hash_const;
                revhashed *= mult_const;
                revhashed ^= revhashed >> XSHIFT;
                std::uint32_t unmixed = *dst;
                unmixed ^= unmixed >> XSHIFT;
                unmixed += MIX_MULT_R*revhashed;
                unmixed *= MIX_INV_L;
                *dst = unmixed;
            }
        }
        for(auto it = std::rbegin(res); it != std::rend(res); ++it) {
            std::uint32_t unhashed = *it;
            unhashed ^= unhashed >> XSHIFT;
            unhashed *= fast_exp(hash_const, std::uint32_t(-1));
            hash_const *= INV_A;
            unhashed ^= hash_const;
            *it = unhashed;
        }

        std::copy(std::begin(res), std::end(res), first);
    }
};
// }}}

// AutoSeeder {{{
#ifndef ENTROPY_CPU
    #if defined(__has_builtin)
        #if __has_builtin(__builtin_readcyclecounter)
            #define ENTROPY_CPU (__builtin_readcyclecounter())
        #endif
    #endif
#endif
#ifndef ENTROPY_CPU
    #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
        #define ENTROPY_CPU (__builtin_ia32_rdtsc())
    #else
        #define ENTROPY_CPU (0)
    #endif
#endif

#ifndef ENTROPY_PID
    #if defined(__unix__) || defined(__unix) || defined(__APPLE__) || defined(__MACH__)
        #include <unistd.h>
        #define ENTROPY_PID (getpid())
    #else
        #define ENTROPY_PID (0)
    #endif
#endif

template<typename SeedSeq>
class AutoSeederT : public SeedSeq {
private:
    using EntropyArray = std::array<uint32_t,13>;

    template<typename T>
    static std::uint32_t crushto32(T x) {
        if(sizeof(T) <= 4) return std::uint32_t(x);

        std::uint64_t res = std::uint64_t(x);
        res *= 0xbc2ad017d719504d;
        return std::uint32_t(res ^ (res>>32));
    }

    template<typename T>
    static std::uint32_t hash_func(T&& x) {
        return crushto32(std::hash<std::remove_reference_t<std::remove_cv_t<T>>>()(std::forward<T>(x)));
    }

    static constexpr std::uint32_t fnv(std::uint32_t h, const char* pos) {
        if(*pos == '\0') return h;
        return fnv((16777619U*h) ^ *pos, pos+1);
    }

    EntropyArray entropy() const {
        constexpr std::uint32_t compile_stamp = fnv(2166136261U, __DATE__ __TIME__ __FILE__);

        static std::uint32_t random_int = std::random_device()();
        random_int += 0xedf19156;

        auto timestamp = crushto32(std::chrono::high_resolution_clock::now().time_since_epoch().count());

        void* malloc_ptr = std::malloc(sizeof(int));
        free(malloc_ptr);
        auto addr_heap  = hash_func(malloc_ptr);
        auto addr_stack = hash_func(&malloc_ptr);

        auto addr_this        = hash_func(this);
        auto addr_static_func = hash_func(static_cast<std::uint32_t (*)(std::uint64_t)>(&AutoSeederT::crushto32));

        auto addr_exit_func = hash_func(&_Exit);
        auto addr_time_func = hash_func(&std::chrono::high_resolution_clock::now);

        auto thread_id = hash_func(std::this_thread::get_id());

#if __cpp_rtti || __GXX_RTTI
        auto type_id = crushto32(typeid(*this).hash_code());
#else
        uint32_t type_id = 0;
#endif

        auto cpu = crushto32(ENTROPY_CPU);
        auto pid = crushto32(ENTROPY_PID);

        return {{
            compile_stamp,
            random_int,
            timestamp,
            addr_heap,
            addr_stack,
            addr_this,
            addr_static_func,
            addr_exit_func,
            addr_time_func,
            thread_id,
            type_id,
            cpu,
            pid,
        }};
    }

    AutoSeederT(EntropyArray ea) : SeedSeq(std::begin(ea),std::end(ea)) {}

public:
    AutoSeederT() : AutoSeederT(entropy()) {}

    const SeedSeq& base() const { return *this; }
          SeedSeq& base()       { return *this; }
};

using AutoSeeder = AutoSeederT<Seeder>;
// }}}

// UniformDistributionType {{{
template<typename T>
struct IsUniformInt {
    static constexpr bool value = std::is_same<T,short             >::value ||
                                  std::is_same<T,int               >::value ||
                                  std::is_same<T,long              >::value ||
                                  std::is_same<T,long long         >::value ||
                                  std::is_same<T,unsigned short    >::value ||
                                  std::is_same<T,unsigned int      >::value ||
                                  std::is_same<T,unsigned long     >::value ||
                                  std::is_same<T,unsigned long long>::value;
};

template<typename T>
struct IsUniformReal {
    static constexpr bool value = std::is_same<T,float      >::value ||
                                  std::is_same<T,double     >::value ||
                                  std::is_same<T,long double>::value;
};

template<typename T>
struct IsUniformByte {
    static constexpr bool value = std::is_same<T,char         >::value ||
                                  std::is_same<T,signed char  >::value ||
                                  std::is_same<T,unsigned char>::value;
};

template<typename T, typename Enable=void>
struct UniformDistribution {};

template<typename T>
struct UniformDistribution<T, std::enable_if_t<IsUniformInt<T>::value>> {
    using type = std::uniform_int_distribution<T>;
};

template<typename T>
struct UniformDistribution<T, std::enable_if_t<IsUniformReal<T>::value>> {
    using type = std::uniform_real_distribution<T>;
};

template<typename T>
using UniformDistributionType = typename UniformDistribution<T>::type;

template<typename T, typename Enable=void>
struct UniformDistributionImpl {};

template<typename T>
class UniformDistributionImpl<T, std::enable_if_t<IsUniformByte<T>::value>> {
private:
    using Short = std::conditional_t<std::is_signed<T>::value, short, unsigned short>;
    using Dist  = UniformDistributionType<Short>;

    Dist dist_;

public:
    using result_type = T;
    using param_type  = typename Dist::param_type;

    explicit UniformDistributionImpl(result_type a=0,
                                     result_type b=std::numeric_limits<result_type>::max())
        : dist_(a,b) {}
    explicit UniformDistributionImpl(const param_type& p)
        : dist_(p) {}
    void reset() {}

    template<typename URNG>
    result_type operator()(URNG& g) {
        return static_cast<result_type>(dist_(g));
    }
    template<typename URNG>
    result_type operator()(URNG& g, const param_type& p) {
        return static_cast<result_type>(dist_(g,p));
    }

    result_type a() const { return static_cast<result_type>(dist_.a()); }
    result_type b() const { return static_cast<result_type>(dist_.b()); }

    param_type param() const { return dist_.param(); }
    void param(const param_type& p) { dist_.param(p); }

    result_type min() const { return a(); }
    result_type max() const { return b(); }

    friend bool operator==(const UniformDistributionImpl& lhs,
                           const UniformDistributionImpl& rhs) {
        return lhs.dist_ == rhs.dist_;
    }
    friend bool operator!=(const UniformDistributionImpl& lhs,
                           const UniformDistributionImpl& rhs) {
        return !(lhs == rhs);
    }
};

template<>
class UniformDistributionImpl<bool> {
private:
    using Dist  = UniformDistributionType<int>;

    Dist dist_;

public:
    using result_type = bool;
    using param_type  = typename Dist::param_type;

    explicit UniformDistributionImpl(result_type a=false, result_type b=true)
        : dist_(a,b) {}
    explicit UniformDistributionImpl(const param_type& p)
        : dist_(p) {}
    void reset() {}

    template<typename URNG>
    result_type operator()(URNG& g) {
        return static_cast<result_type>(dist_(g));
    }
    template<typename URNG>
    result_type operator()(URNG& g, const param_type& p) {
        return static_cast<result_type>(dist_(g,p));
    }

    result_type a() const { return static_cast<result_type>(dist_.a()); }
    result_type b() const { return static_cast<result_type>(dist_.b()); }

    param_type param() const { return dist_.param(); }
    void param(const param_type& p) { dist_.param(p); }

    result_type min() const { return a(); }
    result_type max() const { return b(); }

    friend bool operator==(const UniformDistributionImpl& lhs,
                           const UniformDistributionImpl& rhs) {
        return lhs.dist_ == rhs.dist_;
    }
    friend bool operator!=(const UniformDistributionImpl& lhs,
                           const UniformDistributionImpl& rhs) {
        return !(lhs == rhs);
    }
};

template<typename T>
struct UniformDistribution<T, std::enable_if_t<IsUniformByte<T>::value>> {
    using type = UniformDistributionImpl<T>;
};
template<>
struct UniformDistribution<bool> {
    using type = UniformDistributionImpl<bool>;
};
// }}}

// Rng {{{
template<typename Engine>
class RngT {
private:
    Engine engine_;

public:
    RngT() : engine_(AutoSeeder().base()) {}
    explicit RngT(std::uint32_t seed) : engine_(Seeder({seed})) {}

    void seed(std::uint32_t seed) { engine_.seed(Seeder({seed})); }

    template<typename R,
             template<typename> class DistT=std::normal_distribution,
             typename... Params>
    R variate(Params&&... params) {
        DistT<R> dist(std::forward<Params>(params)...);
        return dist(engine_);
    }

    // [a,b]
    template<typename T,
             std::enable_if_t<IsUniformInt<T>::value, std::nullptr_t> = nullptr>
    T uniform(T a=std::numeric_limits<T>::min(),
              T b=std::numeric_limits<T>::max()) {
        return variate<T,UniformDistributionType>(a, b);
    }

    // [a,b)
    template<typename T,
             std::enable_if_t<IsUniformReal<T>::value, std::nullptr_t> = nullptr>
    T uniform(T a=-std::numeric_limits<T>::max(),
              T b= std::numeric_limits<T>::max()) {
        return variate<T,UniformDistributionType>(a, b);
    }

    // [a,b]
    template<typename T,
             std::enable_if_t<IsUniformByte<T>::value, std::nullptr_t> = nullptr>
    T uniform(T a=std::numeric_limits<T>::min(),
              T b=std::numeric_limits<T>::max()) {
        return variate<T,UniformDistributionType>(a, b);
    }

    // [a,b]
    template<typename T,
             std::enable_if_t<std::is_same<T,bool>::value, std::nullptr_t> = nullptr>
    T uniform(T a=false, T b=true) {
        return variate<T,UniformDistributionType>(a, b);
    }

    template<template<typename> class DistT=UniformDistributionType,
             typename OutputIt,
             typename... Params>
    void generate(OutputIt first, OutputIt last, Params&&... params) {
        using R = std::remove_reference_t<decltype(*first)>;
        DistT<R> dist(std::forward<Params>(params)...);
        std::generate(first, last, [this,&dist]() { return dist(engine_); });
    }

    template<typename RandomIt>
    void shuffle(RandomIt first, RandomIt last) {
        std::shuffle(first, last, engine_);
    }

    template<typename ForwardIt>
    ForwardIt choose(ForwardIt first, ForwardIt last) {
        auto d = std::distance(first, last);
        if(d < 2) return first;

        using distance_type = decltype(d);
        distance_type choice = uniform(distance_type(0), --d);
        return std::next(first, choice);
    }

    template<typename T>
    auto pick(std::initializer_list<T> ilist) -> decltype(*std::begin(ilist)) {
        return *choose(std::begin(ilist), std::end(ilist));
    }

    template<typename BidiIt>
    BidiIt sample(std::size_t size, BidiIt first, BidiIt last) {
        auto total = std::distance(first, last);
        using distance_type = decltype(total);
        return std::stable_partition(first, last, [this,&size,&total](const auto&) {
            --total;
            if(uniform(distance_type(0),total) < size) {
                --size;
                return true;
            }
            else {
                return false;
            }
        });
    }
};

using Rng = RngT<PcgEngine>;
// }}}

// }}}

//--------------------------------------------------------------------

Rng rng;

i64 N;
i64 WMAX;
vector<i64> W;
vector<i64> V;

struct State {
    vector<i64> used;
    vector<i64> unused;
    i64 w;
    i64 v;
};

State state_ini() {
    vector<i64> is(N);
    ALL(iota, is, 0);

    ALL(sort, is, GT_ON([](i64 i) { return f64(V[i]) / f64(W[i]); }));

    i64 wcur = 0;
    i64 vcur = 0;
    vector<i64> used;
    vector<i64> unused;
    used.reserve(N);
    unused.reserve(N);
    for(i64 i : is) {
        i64 w = W[i];
        i64 v = V[i];
        if(wcur+w <= WMAX) {
            wcur += w;
            vcur += v;
            used.emplace_back(i);
        }
        else {
            unused.emplace_back(i);
        }
    }

    return { used, unused, wcur, vcur };
}

State state_neighbor(const State& state) {
    State res(state);
    if(res.unused.empty()) return res;

    {
        auto it = ALL(rng.choose, res.unused);
        res.w += W[*it];
        res.v += V[*it];
        res.used.emplace_back(*it);
        res.unused.erase(it);
    }

    while(res.w > WMAX) {
        auto it = ALL(rng.choose, res.used);
        res.w -= W[*it];
        res.v -= V[*it];
        res.unused.emplace_back(*it);
        res.used.erase(it);
    }

    return res;
}

auto prob_func(f64 temp_ini, i64 iter) {
    // 初期温度 temp_ini, 最終温度 temp_ini/10
    f64 dt = -9.0*temp_ini / (10.0*f64(iter));
    return [temp_ini,dt](f64 dscore, i64 i) -> f64 {
        f64 temp = temp_ini + f64(i)*dt;
        //DBG(dscore, i, temp, exp(-dscore/temp));
        return exp(-dscore/temp);
    };
}

template<typename InputIt>
auto nth_value(InputIt first, InputIt last, i64 n) {
    using T = typename iterator_traits<InputIt>::value_type;
    vector<T> v(first, last);
    nth_element(begin(v), begin(v)+n, end(v));
    return v[n];
}

void solve() {
    constexpr i64 ITER     = 1'000'000;

    f64 temp_ini = f64(ALL(nth_value, V, N/2));

    State state = state_ini();
    DBG(state.w, state.v);

    auto pf = prob_func(temp_ini, ITER);

    i64 score_max = state.v;
    REP(i, ITER) {
        State neighbor = state_neighbor(state);
        i64 dscore = -(neighbor.v - state.v);  // 最小化問題に帰着するため負にする
        if(dscore <= 0) {
            state = move(neighbor);
            chmax(score_max, state.v);
        }
        else {
            f64 prob = pf(f64(dscore), i);
            if(prob > rng.uniform(0.0, 1.0))
                state = move(neighbor);
        }
    }

    PRINTLN(score_max);
}

signed main() {
    RD(N);
    RD(WMAX);

    W.resize(N);
    V.resize(N);
    REP(i, N) {
        RD(W[i]);
        RD(V[i]);
    }

    solve();

    EXIT();
}