#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9 + 5;
struct segment_change {
  int to_add;
  segment_change(int _to_add = 0) : to_add(_to_add) {}
  void reset() { to_add = 0; }
  bool has_change() const { return to_add != 0; }
  segment_change combine(const segment_change &other) const {
    return segment_change(to_add + other.to_add);
  }
};
struct segment {
  int maximum;
  segment(int _maximum = -INF) : maximum(_maximum) {}
  void apply(int, const segment_change &change) { maximum += change.to_add; }
  void join(const segment &other) { maximum = max(maximum, other.maximum); }
  void join(const segment &a, const segment &b) {
    *this = a;
    join(b);
  }
};
struct add_max_seg_tree {
  int tree_n = 0;
  vector<segment> tree;
  vector<segment_change> changes;
  add_max_seg_tree(int n = 0) {
    if (n > 0) init(n);
  }
  void init(int n) {
    tree_n = 1;
    while (tree_n < n) tree_n *= 2;
    tree.assign(2 * tree_n, segment());
    changes.assign(tree_n, segment_change());
  }
  void build(const vector<segment> &initial) {
    int n = initial.size();
    assert(n <= tree_n);
    for (int i = 0; i < n; i++) tree[tree_n + i] = initial[i];
    for (int position = tree_n - 1; position > 0; position--)
      tree[position].join(tree[2 * position], tree[2 * position + 1]);
  }
  void push_down(int position, int length) {
    if (!changes[position].has_change()) return;
    if (2 * position < tree_n) {
      changes[2 * position] = changes[2 * position].combine(changes[position]);
      changes[2 * position + 1] =
          changes[2 * position + 1].combine(changes[position]);
    }
    tree[2 * position].apply(length / 2, changes[position]);
    tree[2 * position + 1].apply(length / 2, changes[position]);
    changes[position].reset();
  }
  void push_all(int a, int b) {
    assert(0 <= a && a < b && b <= tree_n);
    a += tree_n;
    b += tree_n - 1;
    for (int up = 31 - __builtin_clz(tree_n); up > 0; up--) {
      int x = a >> up, y = b >> up;
      push_down(x, 1 << up);
      if (x != y) push_down(y, 1 << up);
    }
  }
  void join_and_apply(int position, int length) {
    tree[position].join(tree[2 * position], tree[2 * position + 1]);
    tree[position].apply(length, changes[position]);
  }
  void join_all(int a, int b) {
    assert(0 <= a && a < b && b <= tree_n);
    a += tree_n;
    b += tree_n - 1;
    int length = 1;
    while (a > 1) {
      a /= 2;
      b /= 2;
      length *= 2;
      join_and_apply(a, length);
      if (a != b) join_and_apply(b, length);
    }
  }
  pair<int, int> right_half[32];
  template <typename T_range_op>
  void process_range(int a, int b, bool needs_join, T_range_op &&range_op) {
    if (a == b) return;
    push_all(a, b);
    int original_a = a, original_b = b;
    int length = 1, r_size = 0;
    for (a += tree_n, b += tree_n; a < b; a /= 2, b /= 2, length *= 2) {
      if (a & 1) range_op(a++, length);
      if (b & 1) right_half[r_size++] = {--b, length};
    }
    for (int i = r_size - 1; i >= 0; i--)
      range_op(right_half[i].first, right_half[i].second);
    if (needs_join) join_all(original_a, original_b);
  }
  segment query(int a, int b) {
    assert(0 <= a && a <= b && b <= tree_n);
    segment answer;
    process_range(a, b, false,
                  [&](int position, int) { answer.join(tree[position]); });
    return answer;
  }
  void update(int a, int b, const segment_change &change) {
    assert(0 <= a && a <= b && b <= tree_n);
    process_range(a, b, true, [&](int position, int length) {
      tree[position].apply(length, change);
      if (position < tree_n)
        changes[position] = changes[position].combine(change);
    });
  }
  void set_value(int index, int value) {
    assert(0 <= index && index < tree_n);
    int current = query(index, index + 1).maximum;
    update(index, index + 1, segment_change(value - current));
  }
};
int N;
vector<int> parent;
vector<vector<int>> children;
vector<int> tour_start, tour_end;
int tour;
void dfs(int node) {
  tour_start[node] = tour++;
  for (int child : children[node]) dfs(child);
  tour_end[node] = tour;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "{";
  for (typename vector<T>::const_iterator vi = v.begin(); vi != v.end(); ++vi) {
    if (vi != v.begin()) os << ", ";
    os << *vi;
  }
  os << "}";
  return os;
}
template <>
ostream &operator<<(ostream &os, const vector<string> &v) {
  os << "{";
  for (vector<string>::const_iterator vi = v.begin(); vi != v.end(); ++vi) {
    if (vi != v.begin()) os << ", ";
    os << "\"" << *vi << "\"";
  }
  os << "}";
  return os;
}
vector<int> solve(vector<int> perm) {
  assert((int)perm.size() == N);
  assert(perm.front() == 1);
  for (int &p : perm) p--;
  parent.assign(N, -1);
  vector<pair<int, int>> events;
  vector<int> stack = {-1};
  for (int x : perm) {
    int erased = -1;
    while (stack.back() > x) {
      erased = stack.back();
      stack.pop_back();
    }
    events.emplace_back(x, stack.back());
    events.emplace_back(erased, x);
    parent[x] = stack.back();
    if (erased >= 0) parent[erased] = x;
    stack.push_back(x);
  }
  children.assign(N, {});
  tour_start.resize(N);
  tour_end.resize(N);
  for (int i = 0; i < N; i++)
    if (parent[i] >= 0) children[parent[i]].push_back(i);
  tour = 0;
  dfs(0);
  vector<int> answers(N, INF);
  add_max_seg_tree tree(N);
  for (int i = 0; i < N; i++) {
    int a = events[2 * i].first;
    int b = events[2 * i].second;
    assert(a >= 0);
    tree.set_value(
        tour_start[a],
        b < 0 ? 1 : tree.query(tour_start[b], tour_start[b] + 1).maximum + 1);
    a = events[2 * i + 1].first;
    b = events[2 * i + 1].second;
    if (a >= 0) {
      tree.update(tour_start[a], tour_end[a], segment_change(+1));
    }
    answers[i] = tree.query(0, N).maximum;
  }
  return answers;
}
vector<int> A;
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cin >> N;
  A.resize(N);
  for (int &a : A) cin >> a;
  int one = find(A.begin(), A.end(), 1) - A.begin();
  vector<int> start_one, end_one;
  for (int i = one; (int)start_one.size() < N; i = (i + 1) % N)
    start_one.push_back(A[i]);
  for (int i = one; (int)end_one.size() < N; i = (i + N - 1) % N)
    end_one.push_back(A[i]);
  vector<int> left = solve(end_one), right = solve(start_one);
  int best_left = 0, best = INF;
  for (int i = 0; i < N; i++) {
    if (max(left[i], right[N - 1 - i]) < best) {
      best = max(left[i], right[N - 1 - i]);
      best_left = i;
    }
  }
  cout << best << ' ' << (one - best_left + N) % N << '\n';
}
