#include <bits/stdc++.h>
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
using namespace std;
using ll = long long;
using lld = long double;
template <typename T>
struct edge {
  long long src, to;
  T cost;
  edge(long long to, T cost) : src(-1), to(to), cost(cost) {}
  edge(long long src, long long to, T cost) : src(src), to(to), cost(cost) {}
  edge &operator=(const long long &x) {
    to = x;
    return *this;
  }
  operator long long() const { return to; }
};
template <typename T>
using Edges = vector<edge<T>>;
template <typename T>
using WeightedGraph = vector<Edges<T>>;
using UnWeightedGraph = vector<vector<ll>>;
template <typename T>
using Matrix = vector<vector<T>>;
const long long MOD = 1000000007;
const long long INF = 1061109567;
const double EPS = 1e-10;
const double PI = acos(-1.0);
const long long dx[4] = {1, 0, -1, 0};
const long long dy[4] = {0, 1, 0, -1};
class UnionFind {
 public:
  vector<long long> par;
  vector<long long> siz;
  UnionFind(long long sz_) : par(sz_), siz(sz_, 1LL) {
    for (long long i = 0; i < sz_; ++i) par[i] = i;
  }
  void init(ll sz_) {
    par.resize(sz_);
    siz.assign(sz_, 1LL);
    for (long long i = 0; i < sz_; ++i) par[i] = i;
  }
  long long root(long long x) {
    while (par[x] != x) {
      x = par[x] = par[par[x]];
    }
    return x;
  }
  bool merge(long long x, long long y) {
    x = root(x);
    y = root(y);
    if (x == y) return false;
    if (siz[x] < siz[y]) swap(x, y);
    siz[x] += siz[y];
    par[y] = x;
    return true;
  }
  bool issame(long long x, long long y) { return root(x) == root(y); }
  long long size(long long x) { return siz[root(x)]; }
};
template <long long mod>
struct ModInt {
  long long x;
  ModInt() : x(0) {}
  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
  ModInt &operator+=(const ModInt &p) {
    if ((x += p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator-=(const ModInt &p) {
    if ((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator*=(const ModInt &p) {
    x = (long long)(1LL * x * p.x % mod);
    return *this;
  }
  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }
  ModInt operator-() const { return ModInt(-x); }
  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
  bool operator==(const ModInt &p) const { return x == p.x; }
  bool operator!=(const ModInt &p) const { return x != p.x; }
  ModInt inverse() const {
    long long a = x, b = mod, u = 1, v = 0, t;
    while (b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }
  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while (n > 0) {
      if (n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }
  friend ostream &operator<<(ostream &os, const ModInt &p) { return os << p.x; }
  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt<mod>(t);
    return (is);
  }
  static long long get_mod() { return mod; }
};
using modint = ModInt<MOD>;
template <typename T>
vector<T> dijkstra(WeightedGraph<T> &g, long long s) {
  const auto INF2 = numeric_limits<T>::max();
  vector<T> dist(g.size(), INF2);
  using Pi = pair<T, long long>;
  priority_queue<Pi, vector<Pi>, greater<Pi>> que;
  dist[s] = 0;
  que.emplace(dist[s], s);
  while (!que.empty()) {
    T cost;
    long long idx;
    tie(cost, idx) = que.top();
    que.pop();
    if (dist[idx] < cost) continue;
    for (auto &e : g[idx]) {
      auto next_cost = cost + e.cost;
      if (dist[e.to] <= next_cost) continue;
      dist[e.to] = next_cost;
      que.emplace(dist[e.to], e.to);
    }
  }
  return dist;
}
template <typename T>
vector<T> bellman_ford(Edges<T> &edges, long long V, long long s) {
  const auto INF2 = numeric_limits<T>::max();
  vector<T> dist(V, INF2);
  dist[s] = 0;
  for (long long i = 0; i < ((V - 1)); ++i) {
    for (auto &e : edges) {
      if (dist[e.src] == INF2) continue;
      dist[e.to] = min(dist[e.to], dist[e.src] + e.cost);
    }
  }
  for (auto &e : edges) {
    if (dist[e.src] == INF2) continue;
    if (dist[e.src] + e.cost < dist[e.to]) return vector<T>();
  }
  return dist;
}
template <typename T>
void warshall_floyd(Matrix<T> &g, T lINF) {
  ll n = g.size();
  for (long long k = 0; k < (n); ++k) {
    for (long long i = 0; i < (n); ++i) {
      for (long long j = 0; j < (n); ++j) {
        if (g[i][k] == lINF || g[k][j] == lINF) continue;
        g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
      }
    }
  }
  return;
}
void fast(void) {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(15);
  return;
}
ll vsum(vector<ll> V) {
  ll res = 0LL;
  ll size = V.size();
  for (long long i = 0; i < (size); ++i) {
    res += V.at(i);
  }
  return res;
}
lld vave(vector<ll> V) {
  lld size = V.size();
  return (lld)vsum(V) / size;
}
ll vmax(vector<ll> V) {
  sort((V).begin(), (V).end());
  reverse((V).begin(), (V).end());
  return V.at(0);
}
ll vmin(vector<ll> V) {
  sort((V).begin(), (V).end());
  return V.at(0);
}
template <typename T>
bool mid1(T a, T b, T c) {
  return (a < b) && (b < c);
}
template <typename T>
bool mid2(T a, T b, T c) {
  return (a <= b) && (b <= c);
}
template <typename T>
void YES(T n) {
  cout << ((n) ? "YES" : "NO") << '\n';
}
template <typename T>
void Yes(T n) {
  cout << ((n) ? "Yes" : "No") << '\n';
}
template <typename T>
void yes(T n) {
  cout << ((n) ? "yes" : "no") << '\n';
}
template <typename T>
void Yay(T n) {
  cout << ((n) ? "Yay!" : ":(") << '\n';
}
inline void in(void) { return; }
template <typename First, typename... Rest>
void in(First &first, Rest &...rest) {
  cin >> first;
  in(rest...);
  return;
}
template <typename T>
void vin(T &V) {
  ll size = V.size();
  for (long long i = 0; i < (size); ++i) {
    cin >> V[i];
  }
  return;
}
inline void out(void) {
  cout << '\n';
  return;
}
template <typename T>
void out(T only) {
  cout << only << '\n';
  return;
}
template <typename First, typename... Rest>
void out(First first, Rest... rest) {
  cout << first << " ";
  out(rest...);
  return;
}
template <typename T>
void vout(T &V) {
  ll size = V.size();
  for (long long i = 0; i < (size); ++i) {
    cout << V.at(i) << '\n';
  }
}
template <typename T>
void vout2(T &V) {
  ll size = V.size();
  for (long long i = 0; i < (size); ++i) {
    cout << V[i] << " \n"[i == (size - 1)];
  }
}
long long gcd(long long a, long long b) { return b != 0 ? gcd(b, a % b) : a; }
long long lcm(long long a, long long b) { return a * b / gcd(a, b); }
string toStrUp(string str) {
  char diff = 'A' - 'a';
  for (long long i = 0; i < (str.size()); ++i) str[i] += diff;
  return str;
}
map<long long, long long> prime_factor(long long n) {
  map<long long, long long> ret;
  for (long long i = 2; i * i <= n; i++) {
    while (n % i == 0) {
      ret[i]++;
      n /= i;
    }
  }
  if (n != 1) ret[n] = 1;
  return ret;
}
bool is_prime(long long x) {
  for (long long i = 2; i * i <= x; i++) {
    if (x % i == 0) return false;
  }
  return true;
}
template <typename T>
vector<T> convert_base(T x, T b) {
  vector<T> ret;
  T t = 1, k = abs(b);
  while (x) {
    ret.emplace_back((x * t) % k);
    if (ret.back() < 0) ret.back() += k;
    x -= ret.back() * t;
    x /= k;
    t *= b / k;
  }
  if (ret.empty()) ret.emplace_back(0);
  reverse(begin(ret), end(ret));
  return ret;
}
template <class T>
inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
signed main() {
  fast();
  long long n, m, k;
  string s;
  in(n);
  vector<ll> A(n);
  vin(A);
  map<ll, ll> mp;
  long long big = 0;
  for (long long i = 0; i < (n); ++i) {
    if (A[i] <= 3199)
      mp[A[i] / 400]++;
    else
      big++;
  }
  long long cnt = 0;
  for (auto p : mp) {
    if (p.second > 0) {
      ++cnt;
    }
  }
  out(cnt, cnt + big);
}
