#include // {{{ #define GET_MACRO(a, b, c, d, NAME, ...) NAME #define REP(...) GET_MACRO(__VA_ARGS__, REP4, REP3, REP2)(__VA_ARGS__) #define REP2(i, a) REP3(i, 0, a) #define REP3(i, a, b) REP4(i, a, b, 1) #define REP4(i, a, b, s) for (int i = (a); i < (int)(b); i += (s)) #define REPR(...) GET_MACRO(__VA_ARGS__, REPR4, REPR3, REPR2)(__VA_ARGS__) #define REPR2(i, a) REPR3(i, 0, a) #define REPR3(i, a, b) REPR4(i, a, b, 1) #define REPR4(i, a, b, s) for (int i = (b)-1; i >= (int)(a); i -= (s)) #define ALL(c) (c).begin(), (c).end() #define DUMP(x) (std::cerr << #x << ':' << ' ' << x << '\n') #define TMPL_T template #define TMPL_TU template #define mut auto #define let const auto using Int = long long; // clang-format off namespace extio { std::string delimiter=" ",pdelimiter=" "; std::string bracket_b="",bracket_e=""; void chdelim(const std::string&s){delimiter=s;} void chpdelim(const std::string&s){pdelimiter=s;} void chbracket(const std::string&b,const std::string&e){bracket_b=b,bracket_e=e;} TMPL_T void pcont(std::ostream&os,const T&x){int c=0;for(const auto&a:x){if(c++)os<&p){os<&x){extio::pcont(os,x);return os;} TMPL_T ostream& operator<<(ostream&os,const set&x){extio::pcont(os,x);return os;} TMPL_T ostream& operator<<(ostream&os,const multiset&x){extio::pcont(os,x);return os;} TMPL_T ostream& operator<<(ostream&os,const deque&x){extio::pcont(os,x);return os;} TMPL_TU ostream& operator<<(ostream&os,const map&x){extio::pcont(os,x);return os;} TMPL_TU ostream& operator<<(ostream&os,const pair&x){extio::ppair(os,x);return os;} } TMPL_TU inline bool chmax(T&x,U a){return x>x;return x;} struct Initializer_ { Initializer_(){ std::cin.tie(0); std::ios::sync_with_stdio(0); std::cout << std::setprecision(10); std::cerr << std::setprecision(10); } } precalc; // clang-format on // }}} //{{{ seg.hpp #ifndef INCLUDE_SEG_HPP #define INCLUDE_SEG_HPP #include #include #include namespace orliv { namespace seg { constexpr std::uint64_t upperPow2(std::uint64_t x, std::uint64_t r = 1) { return x <= r ? r : upperPow2(x, r + r); } template struct Max { using value_type = T; static const value_type default_value = 0; static value_type merge(const value_type &a, const value_type &b) { return std::max(a, b); } static value_type eval(std::int64_t L, std::int64_t R, value_type v, value_type lazy) { return v + lazy; } }; } } #endif //}}} //{{{ seg_tree.hpp #ifndef INCLUDE_SEG_TREE_HPP #define INCLUDE_SEG_TREE_HPP #ifndef INCLUDE_SEG_HPP #include "seg.hpp" #endif #include #include #include namespace orliv { namespace ds { template struct SegTree { using seg_t = typename SegTraits::value_type; static constexpr int N = seg::upperPow2(S); seg_t data[N * 2]; SegTree(seg_t init = SegTraits::default_value) : SegTree(std::vector(N, init), init) {} SegTree(const std::vector &V, seg_t init = SegTraits::default_value) { assert(V.size() <= N); for (int i = 0; i < V.size(); i++) data[i + N - 1] = V[i]; for (int i = V.size(); i < N; i++) data[i + N - 1] = init; for (int i = N - 2; i >= 0; --i) { data[i] = SegTraits::merge(data[i + i + 1], data[i + i + 2]); } } void update(int x, seg_t v) { x += N - 1; data[x] = v; while (x) { x = (x - 1) >> 1; data[x] = SegTraits::merge(data[x + x + 1], data[x + x + 2]); } } void add(int x, seg_t a) { update(x, data[x + N - 1] + a); } seg_t query(int a = 0, int b = N, int x = 0, int l = 0, int r = N) const { if (r <= a || b <= l) return SegTraits::default_value; if (a <= l && r <= b) return data[x]; return SegTraits::merge(query(a, b, x + x + 1, l, (l + r) >> 1), query(a, b, x + x + 2, (l + r) >> 1, r)); } }; } } #endif //}}} using namespace std; signed main() { using max_seg = orliv::ds::SegTree, 3000>; max_seg L(0), R(0); const int MA = 100100; vector> bkt(MA); int N = in(); REP(i, N) { bkt[in()].emplace_back(i); } REP(v, MA) { vector> update; for (int idx : bkt[v]) { update.emplace_back(L.query(0, idx), R.query(idx, N)); } REP(i, bkt[v].size()) { L.update(bkt[v][i], update[i].second + 1); R.update(bkt[v][i], update[i].first + 1); } } cout << max(L.query(), R.query()) << endl; return 0; }