#pragma GCC system_header

#ifndef _LIBCXX_STRING
#define _LIBCXX_STRING

#include <__config>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iterator>
#include <memory>
#include <new>
#include <utility>

_LIBCXX_BEGIN_NAMESPACE_STD

static char __null_char = '\0';

template <class CharT>
class char_traits {
public:
    using char_type = CharT;
    using int_type = int;
    using pos_type = int;
    using off_type = int;
    using state_type = int;

    static constexpr void assign(char_type& r, const char_type& a) { r = a; }

    static constexpr char_type* assign(char_type* p, size_t count, char_type a)
    {
        for (size_t sz = 0; sz < count; sz++) {
            assign(p[sz], a);
        }
        return p;
    }

    static constexpr char_type* move(char_type* dest, const char_type* src, size_t count)
    {
        for (size_t sz = 0; sz < count; sz++) {
            dest[sz] = std::move(src[sz]);
        }
        return dest;
    }

    static constexpr size_t length(const char_type* s)
    {
        return strlen(s);
    }

    static constexpr char_type* copy(char_type* dest, const char_type* src, size_t count)
    {
        for (size_t sz = 0; sz < count; sz++) {
            dest[sz] = src[sz];
        }
        return dest;
    }

    static constexpr int compare(const char_type* a, const char_type* b, size_t count)
    {
        return strncmp(a, b, count);
    }

    static constexpr char_type to_char_type(int_type c) { return static_cast<char_type>(c); }
    static constexpr int_type to_int_type(char_type c) { return static_cast<int_type>(c); }
    static constexpr bool eq_int_type(int_type c1, int_type c2) { return c1 == c2; }

    static constexpr int_type eof() { return -1; }
    static constexpr bool not_eof(int_type a) { return a != eof(); }

    static constexpr bool eq(char_type a, char_type b) { return a == b; }
    static constexpr bool lt(char_type a, char_type b) { return a < b; }
};

template <class CharT, class Traits>
class basic_string_view;

template <class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>>
class basic_string {
public:
    using value_type = CharT;
    using allocator_type = Allocator;
    using size_type = std::size_t;
    using difference_type = std::ptrdiff_t;
    using pointer = CharT*;
    using const_pointer = const CharT*;
    using reference = CharT&;
    using const_reference = const CharT&;
    using iterator = std::__legacy_iter<pointer>;
    using const_iterator = std::__legacy_iter<const_pointer>;
    using reverse_iterator = std::reverse_iterator<iterator>;
    using const_reverse_iterator = std::reverse_iterator<const_iterator>;

    basic_string() = default;

    basic_string(const value_type* str)
    {
        m_size = Traits::length(str);
        ensure_capacity(m_size + 1);
        Traits::copy(m_str, str, m_size);
        Traits::assign(m_str[m_size], '\0');
    }

    basic_string(const value_type* str, size_t size)
    {
        m_size = size;
        ensure_capacity(m_size + 1);
        Traits::copy(m_str, str, m_size);
        Traits::assign(m_str[m_size], '\0');
    }

    template <class Iter>
    constexpr basic_string(Iter first, Iter last)
    {
        m_size = std::distance(first, last);
        ensure_capacity(m_size + 1);
        for (size_t i = 0; first != last; ++first, ++i) {
            Traits::assign(at(i), *first);
        }
    }

    basic_string(const basic_string& s)
    {
        m_size = s.m_size;
        ensure_capacity(m_size + 1);
        Traits::copy(m_str, s.m_str, m_size);
        Traits::assign(m_str[m_size], '\0');
    }

    basic_string(basic_string&& s)
    {
        m_size = s.m_size;
        m_capacity = s.m_capacity;
        m_str = s.m_str;
        s.m_size = s.m_capacity = 0;
        s.m_str = &__null_char;
    }

    ~basic_string()
    {
        clear();
    }

    basic_string& operator=(const basic_string& s)
    {
        m_size = s.m_size;
        ensure_capacity(m_size + 1);
        Traits::copy(m_str, s.m_str, m_size);
        Traits::assign(m_str[m_size], '\0');
        return *this;
    }

    basic_string& operator=(basic_string&& s)
    {
        if (this != &s) {
            clear();
            m_size = s.m_size;
            m_capacity = s.m_capacity;
            m_str = s.m_str;
            s.m_size = s.m_capacity = 0;
            s.m_str = &__null_char;
        }
        return *this;
    }

    basic_string& operator+=(const basic_string& s)
    {
        ensure_capacity(size() + s.size() + 1);
        Traits::copy(&m_str[m_size], s.m_str, s.m_size);
        m_size += s.size();
        Traits::assign(m_str[m_size], '\0');
        return *this;
    }

    basic_string operator+(const basic_string& s) const
    {
        basic_string res(*this);
        res += s;
        return res;
    }

    basic_string operator+(const value_type* s) const
    {
        basic_string res(*this);
        res += basic_string(s);
        return res;
    }

    constexpr allocator_type get_allocator() const { return m_allocator; }

    inline void push_back(const value_type& c)
    {
        ensure_capacity(size() + 2);
        Traits::assign(m_str[m_size], c);
        m_size++;
        Traits::assign(m_str[m_size], '\0');
    }

    inline void pop_back()
    {
        --m_size;
        Traits::assign(m_str[m_size], '\0');
    }

    inline const_reference at(size_t i) const
    {
        return m_str[i];
    }

    inline reference at(size_t i)
    {
        return m_str[i];
    }

    void clear()
    {
        if (m_capacity && m_str != &__null_char) {
            free(m_str);
            m_str = &__null_char;
        }
        m_size = 0;
        m_capacity = 0;
    }

    void resize(size_t count, const value_type& c)
    {
        ensure_capacity(count + 1);
        Traits::assign(&m_str[m_size], count - size(), c);
        m_size = count;
        Traits::assign(m_str[m_size], '\0');
    }
    void resize(size_t count) { resize(count, '\0'); }

    inline size_t size() const { return m_size; }
    inline size_t length() const { return m_size; }
    inline bool empty() const { return size() == 0; }

    inline const_reference operator[](size_t i) const { return at(i); }
    inline reference operator[](size_t i) { return at(i); }

    inline const_reference front() const { return at(0); }
    inline reference front() { return at(0); }

    inline const_reference back() const { return at(size() - 1); }
    inline reference back() { return at(size() - 1); }

    inline const_pointer c_str() const { return m_str; }
    inline const_pointer data() const { return m_str; }

    inline iterator begin() { return iterator(&m_str[0]); }
    inline iterator end() { return iterator(&m_str[m_size]); }

    inline const_iterator cbegin() const { return const_iterator(&m_str[0]); }
    inline const_iterator cend() const { return const_iterator(&m_str[m_size]); }

    inline reverse_iterator rbegin() { return reverse_iterator(&m_str[m_size - 1]); }
    inline reverse_iterator rend() { return reverse_iterator(&m_str[-1]); }

    inline const_reverse_iterator crbegin() const { return const_reverse_iterator(&m_str[m_size - 1]); }
    inline const_reverse_iterator crend() const { return const_reverse_iterator(&m_str[-1]); }

    inline operator std::basic_string_view<CharT, Traits>() const { return std::basic_string_view<CharT, Traits>(data(), size()); }

    bool starts_with(value_type c) const
    {
        if (size() == 0) {
            return false;
        }
        return Traits::eq(at(0), c) == 0;
    }

    bool starts_with(const value_type* s) const
    {
        size_t len = Traits::length(s);
        if (size() < len) {
            return false;
        }

        return Traits::compare(c_str(), s, len) == 0;
    }

private:
    inline void ensure_capacity(size_t new_size)
    {
        int capacity = 4;
        while (new_size > capacity) {
            capacity *= 2;
        }
        grow(capacity);
    }

    void grow(size_t capacity)
    {
        if (capacity < m_capacity) {
            return;
        }

        if (!m_capacity) {
            m_str = m_allocator.allocate(capacity);
        } else {
            auto new_str = m_allocator.allocate(capacity);
            Traits::move(new_str, m_str, m_capacity);
            m_allocator.deallocate(m_str, m_capacity);
            m_str = new_str;
        }
        m_capacity = capacity;
    }

    size_t m_size { 0 };
    size_t m_capacity { 0 };
    value_type* m_str { &__null_char };
    allocator_type m_allocator;
};

typedef basic_string<char> string;

static std::string to_string(int a)
{
    char buf[32];
    std::sprintf(buf, "%d", a);
    return std::string(buf);
}

static std::string to_string(unsigned a)
{
    char buf[32];
    std::sprintf(buf, "%u", a);
    return std::string(buf);
}

template <class CharT, class Traits, class Allocator>
bool operator==(const std::basic_string<CharT, Traits, Allocator>& a, const std::basic_string<CharT, Traits, Allocator>& b)
{
    if (a.size() != b.size()) {
        return false;
    }
    return Traits::compare(a.c_str(), b.c_str(), a.size()) == 0;
}

template <class CharT, class Traits, class Allocator>
bool operator==(const std::basic_string<CharT, Traits, Allocator>& a, const CharT* cstr)
{
    size_t bsize = Traits::length(cstr);
    if (a.size() != bsize) {
        return false;
    }
    return Traits::compare(a.c_str(), cstr, a.size()) == 0;
}

template <class CharT, class Traits, class Allocator>
bool operator<(const std::basic_string<CharT, Traits, Allocator>& a, const std::basic_string<CharT, Traits, Allocator>& b)
{
    int eq = Traits::compare(a.c_str(), b.c_str(), std::min(a.size(), b.size()));
    if (!eq) {
        return eq == -1;
    }
    return a.size() < b.size();
}

_LIBCXX_END_NAMESPACE_STD

#endif // _LIBCXX_STRING