#include <cmath> #include <cstdio> #include <vector> #include <iostream> #include <algorithm> #include <tuple> using namespace std; const int INF = 1000000000; struct type { int num; int posNum; type(int _num = -INF, int _posNum = -1) { num = _num; posNum = _posNum; } type operator+(const type& rhs) const { if (posNum == -1) return rhs; if (rhs.posNum == -1) return *this; if (num > rhs.num) return *this; if (num < rhs.num) return rhs; return type(num, min(posNum, rhs.posNum)); } }; struct update { int sum, v; update(int _sum = 0, int _v = -1) { sum = _sum; v = _v; } update operator+(const update& rhs) const { return update(sum + rhs.sum, max(v, rhs.v)); } type operator()(const type& rhs) const { return type(rhs.num + sum, (v != -1)?v:rhs.posNum); } bool operator!=(const update &rhs) const { return sum != rhs.sum; } }; template<typename T, typename U> struct seg_tree_lazy { int S, H; T def; vector<T> value; U noop; vector<U> prop; seg_tree_lazy<T, U>(int _S, T _def = T(), U _noop = U()) { S = _S, def = _def, noop = _noop; H = 32 - __builtin_clz(S); value.resize(2 * S + 1, def); prop.resize(2 * S + 1, noop); } void apply(int i, U update) { value[i] = update(value[i]); if(i < S) prop[i] = prop[i] + update; } void rebuild(int i) { for (int l = i/2; l; l /= 2) { T combined = value[2*l] + value[2*l+1]; value[l] = prop[l](combined); } } void propagate(int i) { for (int h = H; h > 0; h--) { int l = i >> h; if (prop[l] != noop) { apply(2*l, prop[l]); apply(2*l+1, prop[l]); prop[l] = noop; } } } void upd(int i, int j, U update) { i += S, j += S; propagate(i), propagate(j); for (int l = i, r = j; l <= r; l /= 2, r /= 2) { if((l&1) == 1) apply(l++, update); if((r&1) == 0) apply(r--, update); } rebuild(i), rebuild(j); } T query(int i, int j){ i += S, j += S; propagate(i), propagate(j); T res = def; for(; i <= j; i /= 2, j /= 2){ if((i&1) == 1) res = res + value[i++]; if((j&1) == 0) res = res + value[j--]; } return res; } }; int main() { int N; scanf("%d", &N); vector<int> V(N); for (int &x : V) { scanf("%d", &x); x--; } bool inorder = true; for (int i = 0; i < N; i++) if (V[i] != i) inorder = false; if (inorder) { printf("Cool Array\n"); return 0; } vector<int> invV(N); for (int i = 0; i < N; i++) invV[V[i]] = i; int S = N; while (__builtin_popcount(S) != 1) S++; seg_tree_lazy<type, update> segtree(S); // find special Js vector<int> J, VJ; int last = -1; for (int j = N-1; j >= 0; j--) { if (last != -1 && V[j] > last) continue; J.push_back(j); VJ.push_back(V[j]); last = V[j]; segtree.upd(j, j, update(INF, j)); } reverse(VJ.begin(), VJ.end()); reverse(J.begin(), J.end()); // initialize with "> V[j]" for all j for (int i = 0; i < N; i++) { int pos = upper_bound(VJ.begin(), VJ.end(), V[i]) - VJ.begin(); if (pos == J.size()) continue; pos = max(J[pos], i+1); segtree.upd(pos, S-1, update(-1)); } last = -1; tuple<int, int, int> best{INF, 0, 0}; for (int i = 0; i < N; i++) { int pos = upper_bound(VJ.begin(), VJ.end(), V[i]) - VJ.begin(); if (pos < J.size()) { pos = max(J[pos], i+1); segtree.upd(pos, S-1, update(1)); } if (last != -1 && V[i] < last) { segtree.upd(i + 1, S-1, update(-1)); continue; } for (int k = last + 1; k <= V[i]; k++) { if (invV[k] <= i) continue; segtree.upd(invV[k] + 1, S-1, update(1)); } // include i itself pos = upper_bound(VJ.begin(), VJ.end(), V[i]) - VJ.begin(); int limsup = S-1; if (pos != VJ.size()) limsup = J[pos]-1; int liminf = i+1; if (limsup >= liminf) segtree.upd(liminf, limsup, update(1)); type ans = segtree.query(i+1, N-1); best = min(best, tuple<int, int, int>{-ans.num, i, ans.posNum}); last = V[i]; if (limsup >= liminf) segtree.upd(liminf, limsup, update(-1)); } printf("%d %d\n", get<1>(best) + 1, get<2>(best) + 1); return 0; }