/* #region Head */ // #include #include #include #include #include // assert.h #include // math.h #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using ll = long long; using ull = unsigned long long; using ld = long double; using pll = pair; template using vc = vector; template using vvc = vc>; using vll = vc; using vvll = vvc; using vld = vc; using vvld = vvc; using vs = vc; using vvs = vvc; template using um = unordered_map; template using pq = priority_queue; template using pqa = priority_queue, greater>; template using us = unordered_set; #define TREP(T, i, m, n) for (T i = (m), i##_len = (T)(n); i < i##_len; ++(i)) #define TREPM(T, i, m, n) for (T i = (m), i##_max = (T)(n); i <= i##_max; ++(i)) #define TREPR(T, i, m, n) for (T i = (m), i##_min = (T)(n); i >= i##_min; --(i)) #define TREPD(T, i, m, n, d) for (T i = (m), i##_len = (T)(n); i < i##_len; i += (d)) #define TREPMD(T, i, m, n, d) for (T i = (m), i##_max = (T)(n); i <= i##_max; i += (d)) #define REP(i, m, n) for (ll i = (m), i##_len = (ll)(n); i < i##_len; ++(i)) #define REPM(i, m, n) for (ll i = (m), i##_max = (ll)(n); i <= i##_max; ++(i)) #define REPR(i, m, n) for (ll i = (m), i##_min = (ll)(n); i >= i##_min; --(i)) #define REPD(i, m, n, d) for (ll i = (m), i##_len = (ll)(n); i < i##_len; i += (d)) #define REPMD(i, m, n, d) for (ll i = (m), i##_max = (ll)(n); i <= i##_max; i += (d)) #define REPI(itr, ds) for (auto itr = ds.begin(); itr != ds.end(); itr++) #define REPIR(itr, ds) for (auto itr = ds.rbegin(); itr != ds.rend(); itr++) #define ALL(x) begin(x), end(x) #define SIZE(x) ((ll)(x).size()) #define PERM(c) \ sort(ALL(c)); \ for (bool c##p = 1; c##p; c##p = next_permutation(ALL(c))) #define UNIQ(v) v.erase(unique(ALL(v)), v.end()); #define CEIL(a, b) (((a) + (b)-1) / (b)) #define endl '\n' constexpr ll INF = 1'010'000'000'000'000'017LL; constexpr int IINF = 1'000'000'007LL; constexpr ll MOD = 1'000'000'007LL; // 1e9 + 7 // constexpr ll MOD = 998244353; constexpr ld EPS = 1e-12; constexpr ld PI = 3.14159265358979323846; template istream &operator>>(istream &is, vc &vec) { // vector 入力 for (T &x : vec) is >> x; return is; } template ostream &operator<<(ostream &os, const vc &vec) { // vector 出力 (for dump) os << "{"; REP(i, 0, SIZE(vec)) os << vec[i] << (i == i_len - 1 ? "" : ", "); os << "}"; return os; } template ostream &operator>>(ostream &os, const vc &vec) { // vector 出力 (inline) REP(i, 0, SIZE(vec)) os << vec[i] << (i == i_len - 1 ? "\n" : " "); return os; } template istream &operator>>(istream &is, array &arr) { // array 入力 REP(i, 0, SIZE(arr)) is >> arr[i]; return is; } template ostream &operator<<(ostream &os, const array &arr) { // array 出力 (for dump) os << "{"; REP(i, 0, SIZE(arr)) os << arr[i] << (i == i_len - 1 ? "" : ", "); os << "}"; return os; } template istream &operator>>(istream &is, pair &pair_var) { // pair 入力 is >> pair_var.first >> pair_var.second; return is; } template ostream &operator<<(ostream &os, const pair &pair_var) { // pair 出力 os << "(" << pair_var.first << ", " << pair_var.second << ")"; return os; } // map, um, set, us 出力 template ostream &out_iter(ostream &os, const T &map_var) { os << "{"; REPI(itr, map_var) { os << *itr; auto itrcp = itr; if (++itrcp != map_var.end()) os << ", "; } return os << "}"; } template ostream &operator<<(ostream &os, const map &map_var) { return out_iter(os, map_var); } template ostream &operator<<(ostream &os, const um &map_var) { os << "{"; REPI(itr, map_var) { auto [key, value] = *itr; os << "(" << key << ", " << value << ")"; auto itrcp = itr; if (++itrcp != map_var.end()) os << ", "; } os << "}"; return os; } template ostream &operator<<(ostream &os, const set &set_var) { return out_iter(os, set_var); } template ostream &operator<<(ostream &os, const us &set_var) { return out_iter(os, set_var); } template ostream &operator<<(ostream &os, const pq &pq_var) { pq pq_cp(pq_var); os << "{"; if (!pq_cp.empty()) { os << pq_cp.top(), pq_cp.pop(); while (!pq_cp.empty()) os << ", " << pq_cp.top(), pq_cp.pop(); } return os << "}"; } // tuple 出力 template ostream &operator<<(ostream &os, tuple &a) { if constexpr (N < std::tuple_size_v>) { os << get(a); if constexpr (N + 1 < std::tuple_size_v>) { os << ' '; } else if constexpr (end_line) { os << '\n'; } return operator<<(os, a); } return os; } template void print_tuple(tuple &a) { operator<<<0, true>(cout, a); } void pprint() { cout << endl; } template void pprint(Head &&head, Tail &&...tail) { cout << head; if (sizeof...(Tail) > 0) cout << ' '; pprint(move(tail)...); } // dump #define DUMPOUT cerr void dump_func() { DUMPOUT << endl; } template void dump_func(Head &&head, Tail &&...tail) { DUMPOUT << head; if (sizeof...(Tail) > 0) DUMPOUT << ", "; dump_func(move(tail)...); } // chmax (更新「される」かもしれない値が前) template > bool chmax(T &xmax, const U &x, Comp comp = {}) { if (comp(xmax, x)) { xmax = x; return true; } return false; } // chmin (更新「される」かもしれない値が前) template > bool chmin(T &xmin, const U &x, Comp comp = {}) { if (comp(x, xmin)) { xmin = x; return true; } return false; } // ローカル用 #ifndef ONLINE_JUDGE #define DEBUG_ #endif #ifdef DEBUG_ #define DEB #define dump(...) \ DUMPOUT << " " << string(#__VA_ARGS__) << ": " \ << "[" << to_string(__LINE__) << ":" << __FUNCTION__ << "]" << endl \ << " ", \ dump_func(__VA_ARGS__) #else #define DEB if (false) #define dump(...) #endif #define VAR(type, ...) \ type __VA_ARGS__; \ cin >> __VA_ARGS__; template istream &operator,(istream &is, T &rhs) { return is >> rhs; } template ostream &operator,(ostream &os, const T &rhs) { return os << ' ' << rhs; } struct AtCoderInitialize { static constexpr int IOS_PREC = 15; static constexpr bool AUTOFLUSH = false; AtCoderInitialize() { ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); cout << fixed << setprecision(IOS_PREC); if (AUTOFLUSH) cout << unitbuf; } } ATCODER_INITIALIZE; void Yn(bool p) { cout << (p ? "Yes" : "No") << endl; } void YN(bool p) { cout << (p ? "YES" : "NO") << endl; } /* #endregion */ // #include // using namespace atcoder; /* #region MexSet */ template class MexSet { set> s; // 閉区間の集合 public: // コンストラクタ,番兵を追加する MexSet() { s.emplace(TMIN, TMIN), s.emplace(TMAX, TMAX); } // 値が集合に含まれるかどうかを返す bool contains(const T x) const { const pair needle = {x + 1, x + 1}; auto it = prev(s.lower_bound(needle)); auto [l, u] = *it; return l <= x && x <= u; } // 値を追加する // 値が既に追加されている場合は false を返す bool insert(const T x) { const pair needle = {x + 1, x + 1}; auto nit = s.lower_bound(needle); auto it = prev(nit); auto [l, u] = *it; auto [nl, nu] = *nit; // 既に追加されているときを弾く if (l <= x && x <= u) return false; if (u == x - 1) { // it の区間を右に1つ伸ばす if (nl == x + 1) { // nit の区間の左端と接するとき,区間を結合する s.erase(it), s.erase(nit); s.emplace(l, nu); } else { s.erase(it); s.emplace(l, x); } } else { if (nl == x + 1) { // nit の区間を左に1つ伸ばす s.erase(nit); s.emplace(x, nu); } else { s.emplace(x, x); } } return true; } // 値を削除する // 値が最初から追加されていない場合は false を返す bool erase(const T x) { const pair needle = {x + 1, x + 1}; auto it = prev(s.lower_bound(needle)); auto [l, u] = *it; // 既に削除されているときを弾く if (x < l || u < x) return false; s.erase(it); if (x == l) { // 区間の左側を1つ縮める if (l < u) s.emplace(l + 1, u); } else if (x == u) { // 区間の右側を1つ縮める if (l < u) s.emplace(l, u - 1); } else { s.emplace(l, x - 1), s.emplace(x + 1, u); } return true; } // 閉区間を追加する // 区間 [l, r] のうち既に含まれている区間数を M として O(M log SIZE(s)) // 最悪時 O((r-l) log SIZE(s)) // 未 verify bool insert_range(const T l, const T r) { assert(l <= r); const pair needle0 = {l + 1, l + 1}; auto nit0 = s.lower_bound(needle0); auto it0 = prev(nit0); auto [l0, u0] = *it0; // auto [nl0, nu0] = *nit0; T L = l; auto LI = nit0; if (l0 <= l && l <= u0) { // it0 の区間に l が含まれている L = l0; LI = it0; if (r <= u0) return false; // [l, r] は完全に it0 に包含されている } else if (l - 1 == u0) { // [l, r] は左隣の区間と隣接しているので連結する L = l0; LI = it0; } const pair needle1 = {r + 1, r + 1}; auto nit1 = s.lower_bound(needle1); auto it1 = prev(nit1); auto [l1, u1] = *it1; auto [nl1, nu1] = *nit1; T R = r; auto RI = nit1; // set::erase は半開区間なので,it1 まで消すならその次を保持 if (l1 <= r && r <= u1) { // it1 の区間に r が含まれている R = u1; } else if (r + 1 == nl1) { // [l, r] は右隣の区間と隣接しているので連結する R = nu1; RI = next(nit1); } if (LI->first < RI->first) { s.erase(LI, RI); } s.emplace(L, R); return true; } // 閉区間を削除する // 区間 [l, r] のうち既に含まれている区間数を M として O(M log SIZE(s)) // 最悪時 O((r-l) log SIZE(s)) // 未 verify bool erase_range(const T l, const T r) { assert(l <= r); const pair needle0 = {l + 1, l + 1}; auto nit0 = s.lower_bound(needle0); auto it0 = prev(nit0); auto [l0, u0] = *it0; auto [nl0, nu0] = *nit0; T L = l0; T LL = l0 - 1; auto LI = nit0; if (l0 <= l && l <= u0) { // it0 の区間に l が含まれている // [l0, l-1] は残す L = l0; LL = l - 1; LI = it0; } else { // [l, r] は it0 よりも右側 if (r < nl0) return false; // [l, r] は it0 と nit0 の狭間に完全に包含されている } const pair needle1 = {r + 1, r + 1}; auto nit1 = s.lower_bound(needle1); auto it1 = prev(nit1); auto [l1, u1] = *it1; // auto [nl1, nu1] = *nit1; T R = u1 + 1; T RR = u1; auto RI = nit1; // set::erase は半開区間なので,it1 まで消すならその次を保持 if (l1 <= r && r <= u1) { // it1 の区間に r が含まれている R = r + 1; } if (LI->first < RI->first) { s.erase(LI, RI); } if (L <= LL) s.emplace(L, LL); if (R <= RR) s.emplace(R, RR); return true; } // 集合に含まれる値のうち, x 以上で最小のものを返す // 存在しない場合は TMAX を返す T get_minleft_included(const T x) const { const pair needle = {x + 1, x + 1}; auto nit = s.lower_bound(needle); auto it = prev(nit); auto [l, u] = *it; auto [nl, nu] = *nit; if (l <= x && x <= u) return x; return nl; } // 集合に含まれる値のうち, x 以下で最大のものを返す // 存在しない場合は TMIN を返す // 未 verify T get_maxright_included(const T x) const { const pair needle = {x + 1, x + 1}; auto nit = s.lower_bound(needle); auto it = prev(nit); auto [l, u] = *it; // auto [nl, nu] = *nit; if (l <= x && x <= u) return x; return u; } // 集合に含まれない値のうち, x 以上で最小のものを返す T get_minleft_excluded(const T x = 0) const { const pair needle = {x + 1, x + 1}; auto [l, u] = *prev(s.lower_bound(needle)); if (l <= x && x <= u) { return u + 1; } else { return x; } } // 集合に含まれない値のうち, x 以下で最大のものを返す // 未 verify T get_maxright_excluded(const T x = 0) const { const pair needle = {x + 1, x + 1}; auto [l, u] = *prev(s.lower_bound(needle)); if (l <= x && x <= u) { return l - 1; } else { return x; } } // mex を返す // (つまり,集合に含まれない最小の非負整数を返す) T mex() const { return get_minleft_excluded(0); } friend ostream &operator<<(ostream &os, const MexSet &x) { os << "MexSet{"; for (auto [l, r] : x.s) { os << '['; if (l == TMIN) os << "TMIN"; else if (l == TMAX) os << "TMAX"; else os << l; os << ", "; if (r == TMIN) os << "TMIN"; else if (r == TMAX) os << "TMAX"; else os << r; os << ']'; if (r != TMAX) os << ", "; } os << '}'; return os; } }; /* #endregion */ // Problem void solve() { VAR(ll, n); vll p(n); cin >> p; // REP(i, 0, n) p[i]--; // i 回目で i 点なので,後ろの方で大きい得点を得たほうが得になる // 得られる得点は差の大きさによらないので,できるだけ小さい数で対応したい ll score = 0; MexSet<> ms; ms.insert_range(1, n); REPR(i, n, 1) { ll pi = p[i - 1]; // ll candidate0 = ms.get_minleft_included(pi + 1); if (candidate0 != INF) { // dump(candidate0, pi + 1); ms.erase(candidate0); score += i; } else { if (ms.contains(pi)) { ms.erase(pi); // dump(pi); } else { ll candidate1 = ms.get_minleft_included(1); // dump(candidate1); ms.erase(candidate1); score -= i; } } } pprint(score); } // entry point int main() { solve(); return 0; }