#include using namespace std; typedef long long ll; typedef pair Pll; typedef pair Pdd; template using MaxHeap = priority_queue; template using MinHeap = priority_queue, greater>; #define REP(i, n) for(int i = 0; i < n; i++) #define REPR(i, n) for(int i = n; i >= 0; i--) #define FOR(i, m, n) for(int i = m; i < n; i++) #define FORR(i, m, n) for(int i = m; i >= n; i--) #define INF (ll)1e17 #define MOD ((ll)1e9+7) #define ALL(v) v.begin(), v.end() #define SZ(x) ((int)(x).size()) #define y0 y3487465 #define y1 y8687969 #define j0 j1347829 #define j1 j234892 #define next asdnext #define prev asdprev #define bit(n) (1LL<<(n)) #define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() ); #define cauto const auto& #define pb push_back #define mp make_pair #define println(v) cout << v << "\n"; #define debug(v) if (debug_mode) cerr << v << "\t"; #define debugln(v) if (debug_mode) cerr << v << "\n"; #define debugP(v) if (debug_mode) cerr << "(" << v.first << ", " << v.second << ")\t"; #define dump(x) if (debug_mode) cerr << #x << " = " << (x) << "\t"; #define SP << " " << #define TB << "\t" << #ifdef _LOCAL bool debug_mode = true; #else bool debug_mode = false; #endif void show(const vector& arr, bool show_index = false, ll w = 4) { if (!debug_mode) return; ll max_value = 0; REP(i, SZ(arr)) { if (abs(INF - arr[i]) >= 1e5) max_value = max(max_value, arr[i]); } w = max(w, SZ(to_string(max_value))+1LL); if (show_index) { REP(i, arr.size()) { cout << right << setw(w) << i; } cout << endl; } REP(i, arr.size()){ if (abs(INF - arr[i]) < 1e5) { cout << right << setw(w) << (arr[i] == INF ? "INF" : "inf"); } else { cout << right << setw(w) << arr[i]; } } cout << endl; } void show(const vector>& arr, ll w = 4) { if (!debug_mode) return; int M = arr.size(), N = arr[0].size(); ll max_value = 0; REP(i, M) REP(j, N) { if (abs(INF - arr[i][j]) >= 1e5) max_value = max(max_value, arr[i][j]); } w = max(w, SZ(to_string(max_value))+1LL); cout << right << setw(w) << "#"; REP(i, SZ(arr[0])) { cout << right << setw(w) << i; } cout << endl; REP(i, SZ(arr)) { cout << right << setw(w) << i; REP(j, SZ(arr[0])) { if (abs(INF - arr[i][j]) < 1e5) { cout << right << setw(w) << (arr[i][j] == INF ? "INF" : "inf"); } else { cout << right << setw(w) << arr[i][j]; } } cout << endl; } cout << endl; } void show(const vector>>& arr, ll w = 4) { if (!debug_mode) return; REP(i, arr.size()) { println("i: " + to_string(i)); show(arr[i], w); } cout << endl; } inline vector>> make_vector(ll i, ll j, ll k) { vector>> v(i, vector>(j, vector(k, 0))); return v; } inline vector> make_vector(ll i, ll j) { vector> v(i, vector(j, 0)); return v; } template InputIterator adv(InputIterator x, typename std::iterator_traits::difference_type n) { advance(x, n); return x; } class mod { static ll fact[]; public: template static ll mul(A... args) { ll res = 1; for (ll i : std::initializer_list{args...}) { res = (res * i) % MOD; } return res; } static ll power(ll base, ll exp) { if (exp == 0) return 1; if (exp & 1) { return mul(base, power(base, exp - 1)); } else { ll p = power(base, exp / 2); return mul(p, p); } } static void calc_factorial(int n) { fact[0] = 1; FOR(i, 1, n+1) { fact[i] = mul(fact[i-1], i); } } static ll factorial(int n) { if (fact[n] != 0) return fact[n]; if (n == 0) return 1; return fact[n] = mul(n, factorial(n - 1)); } static ll inverse(int n) { return power(n, MOD - 2); } static ll comb(int n, int r) { if (r < 0 || r > n) return 0; return mul(factorial(n), inverse(factorial(n - r)), inverse(factorial(r))); } template static ll div(ll dividend, A... args) { ll res = dividend; for (ll i : std::initializer_list{args...}) { res = mul(res, inverse(i)); } return res; } template static ll add(A... args) { ll res = 0; for (ll i : std::initializer_list{args...}) { res = (res + i) % MOD; } return res; } template static ll sub(ll l, A... args) { ll res = l; for (ll i : std::initializer_list{args...}) { res = (res - i + MOD) % MOD; } return res; } }; ll mod::fact[(int) 2e6 + 1]; int ni() { int i; cin >> i; return i; } ll nll() { ll l; cin >> l; return l; } class math { public: /* * n <= a/b なる最大の整数nを返す */ static ll floor(ll a, ll b) { if (b < 0) { a *= -1; b *= -1; } if (a > 0) { //絶対値の小さい方に丸められる(正なら負の方向) return a/b; } else { //よくある切り上げのテクニックの切り捨て版 return (a-b+1)/b; } } /* * n >= a/b なる最小の整数nを返す */ static ll ceil(ll a, ll b) { if (b < 0) { a *= -1; b *= -1; } if (a > 0) { //よくある切り上げのテクニック return (a+b-1)/b; } else { //絶対値の小さい方に丸められる(負なら正の方向) return a/b; } } /* * aとbの最大公約数を求める */ static ll gcd(ll a, ll b) { long M = max(a, b); long m = min(a, b); if (m == 0) { return M; } return gcd(m, M%m); } /* * aとbの最小公倍数を求める */ static ll lcm(ll a, ll b) { return a * b / gcd(a, b); } /* * n(2^62以下)の平方根の整数部分を返す * doubleの精度には限界があるので整数の二分探索で求める */ static ll sqrt(ll n) { ll high = 3037000000LL; // sqrt(2^63-1) = sqrt(9.223372e+18) ll low = 0; ll mid; while(high - low > 1) { mid = (high + low) / 2; if (mid * mid <= n) { low = mid; } else { high = mid; } } return low; } }; int main() { ll N, M; cin >> N >> M; vector A(N); REP(i, N) cin >> A[i]; sort(ALL(A)); ll ansmax = 0, ansmin = 0; REP(i, N) { if (i == 0 || A[i-1] != A[i]) ansmax++; } if (N == M && A[0] == A[N-1]) ansmin = 1; cout << ansmax SP ansmin << endl; return 0; }