Go: package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"sort"
	"strconv"
)

func main() {
	fmt.Println(resolve(parseProblem(os.Stdin)))
}

func parseProblem(r io.Reader) int {
	const (
		initialBufSize = 100000
		maxBufSize     = 1000000
	)
	buf := make([]byte, initialBufSize)

	sc := bufio.NewScanner(r)
	sc.Buffer(buf, maxBufSize)
	sc.Split(bufio.ScanWords) // bufio.ScanLines

	return scanInt(sc)
}

func resolve(n int) (int, int) {
	ds := enumDivisors(n)
	max := len(ds) - 1

	cand := map[int]struct{}{}
	for _, d := range ds {
		cand[d] = struct{}{}
	}
	delete(cand, n)
	sort.Sort(sort.Reverse(sort.IntSlice(ds)))
	min := 0
	for _, k := range ds {
		if _, ok := cand[k]; !ok {
			continue
		}
		if len(cand) == 0 {
			break
		}
		for _, kk := range enumDivisors(k) {
			delete(cand, kk)
		}
		min++
	}
	return min, max
}

func pow(n, i int) (res int) {
	res = 1
	for i > 0 {
		if i&1 == 1 {
			res *= n
		}
		i >>= 1
		n *= n
	}
	return res
}

func enumDivisors(n int) (r []int) {
	max := int(math.Sqrt(float64(n))) + 1
	for i := 1; i < max; i++ {
		if n%i == 0 {
			r = append(r, i)
			if n/i != i {
				r = append(r, n/i)
			}
		}
	}
	sort.Sort(sort.IntSlice(r))
	return r
}

// snip-scan-funcs
func scanInt(sc *bufio.Scanner) int {
	sc.Scan()
	i, _ := strconv.Atoi(sc.Text())
	return int(i)
}
func scanString(sc *bufio.Scanner) string {
	sc.Scan()
	return sc.Text()
}

C++: // vim: shiftwidth=2 expandtab foldmethod=marker

// include {{{
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// }}}

// debug(...) {{{
#ifdef LOCAL_DEBUG
#include "./debug.h"
#else
bool debug_enabled = false;
#define debug(...)
#define debugn(...)
#define debug_reset()
#endif

// }}}

// bin {{{
template <class T>
std::string bin(int bits, const T& x) {
  char buf[bits + 1];
  buf[bits] = '\0';
  for (int i = 0; i < bits; i++) {
    if ((x >> i) & 1) {
      buf[bits - i - 1] = '1';
    } else {
      buf[bits - i - 1] = '0';
    }
  }
  return std::string(buf);
}
std::string bin(int x) {
  if (x < 0) return bin(32, x);
  for (int i = 4; i < 31; i++) {
    int y = 1 << i;
    if (x < y) return bin(i, x);
  }
  return bin(32, x);
}
// }}}

// misc {{{
using namespace std;
template <class T, class U>

using umap = unordered_map<T, U>;
template <class T>
using uset = unordered_set<T>;

typedef long long ll;

#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define rep2(i, s, n) for (int i = (s); i < (int)(n); i++)

template <class T>
void sort(T& arr) {  // {{{
  std::sort(arr.begin(), arr.end());
}  // }}}
template <class T, class By>
void sort_by(T& arr, By by) {  // {{{
  std::sort(arr.begin(), arr.end(), [by](auto l, auto r) { return by(l) < by(r); });
}  // }}}

template <class T>
void reverse(T& arr) {  // {{{
  std::reverse(arr.begin(), arr.end());
}  // }}}

class Random {  // {{{
 public:
  std::uniform_int_distribution<> uniform_int;
  std::mt19937 rnd;
  std::bernoulli_distribution bern_dist;
  int uniform(int l, int r) {
    return uniform_int(rnd, std::uniform_int_distribution<>::param_type(l, r));
  }
  int next(int N) {
    return uniform(0, N - 1);
  }
  int bern(double p) {
    return bern_dist(rnd, std::bernoulli_distribution::param_type(p));
  }
};  // }}}

template <class A>
ostream& out_vec(const vector<A>& x, const string& sep) {  // {{{
  rep(i, x.size()) {
    cout << x[i];
    if (i < x.size() - 1) cout << sep;
  }
  return cout;
}  // }}}

bool ends_with(const string& s, const string& x) {
  if(s.length() < x.length()) return false;
  for(int i = 0; i < x.size(); i++) {
    if(s[s.size() - 1 - i] != x[x.size() - 1 - i]) return false;
  }
  return true;
}
// }}}

// modulo {{{
ll modpow(ll a, ll n, ll mod) {
  ll res = 1;
  while (n > 0) {
    if (n & 1) res = res * a % mod;
    a = a * a % mod;
    n >>= 1;
  }
  return res;
}

ll modplus(ll a, ll b, ll mod) {
  ll x = ((a % mod) + (b % mod)) % mod;
  if (x < 0) x += mod;
  return x;
}

ll modminus(ll a, ll b, ll mod) {
  return modplus(a, -b, mod);
}

// }}}

class UnionFind {  // {{{
  vector<int> parent;

 public:
  UnionFind(int N) : parent(N) {
    rep(i, N) parent[i] = i;
  }

  int root(int x) {
    if (parent[x] == x)
      return x;
    else
      return parent[x] = root(parent[x]);
  }

  void unite(int x, int y) {
    int rx = root(x);
    int ry = root(y);
    if (rx != ry) { parent[rx] = ry; }
  }
};  // }}}

// modulo {{{
// https://qiita.com/drken/items/3b4fdf0a78e7a138cd9a
long long modinv(long long a, long long m) {
  long long b = m, u = 1, v = 0;
  while (b) {
    long long t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= m;
  if (u < 0) u += m;
  return u;
}

ll modfact(ll a, ll m) {
  ll x = 1;
  for (ll i = 2; i <= a; i++) {
    x *= i;
    x %= m;
  }
  return x;
}

ll mod_P(ll n, ll r, ll m) {
  ll x = 1;
  for (ll i = n - r + 1; i <= n; i++) {
    x *= i;
    x %= m;
  }
  return x;
}

ll mod_C(ll n, ll r, ll m) {
  return mod_P(n, r, m) * modinv(modfact(r, m), m) % m;
}

// }}}

// main {{{
void solve();
int main() {
  cout << setprecision(20);
  solve();
}
// }}}

void solve() {
  ll N;
  cin >> N;
  vector<bool> sieve(1e7);
  vector<ll> primes;
  for(ll i = 2; i * i <= N; i++) {
    if(sieve[i]) continue;
    primes.push_back(i);
    for(ll j = i * 2; j < sieve.size(); j += i) sieve[j] = true; 
  }
  debugn(primes);
  vector<ll> c;
  ll M = N;
  rep(i, primes.size()) {
    int x = 0;
    while(M % primes[i] == 0) {
      x++;
      M /= primes[i];
    }
    if(x > 0) {
      debugn(primes[i], x);
      c.emplace_back(x);
    }
  }
  if(M > 1) c.emplace_back(1);
  debugn(c);
  ll makusu = 1;
  rep(i, c.size()) makusu *= (c[i] + 1);
  makusu--;

  ll minn = c.size();

  cout << minn << ' ' << makusu << endl;
}

C++: #include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define int long long

signed main(){
    int N;
    cin >> N;
    vector<int> diviser;

    for(int i=1;i*i<=N;i++){
        if(N % i == 0){
            diviser.emplace_back(i);
            if(i*i != N) diviser.emplace_back(N/i);
        }
    }

    sort(diviser.begin(),diviser.end());

    if(diviser.size() == 2) cout << 1 << " " << 1 << endl;
    else {
        vector<bool> possible(diviser.size()-1,true);
        for(int i=possible.size()-1;i>=0;i--){
            if(!possible[i]) continue;
            for(int j=0;j<i;j++) {
                if(diviser[i] % diviser[j] == 0) possible[j] = false;
            }
        }

        int MIN = 0;
        for(int i=0;i<possible.size();i++) MIN += possible[i];

        cout << MIN << " " << diviser.size() - 1 << endl;
    }
}

C++: #include <iostream>
#include <map>
using namespace std;
map<long long,int> mp;
int main(){
	long long i,n;
	cin >> n;
	for(i=2;i*i<=n;i++){
		while(n%i==0){
			n /= i;
			mp[i]++;
		}
	}
	if(n!=1) mp[n]++;
	int mn = 0,mx = 1;
	for(auto x: mp){
		mn++;
		mx *= (x.second + 1);
	}
	mx--;
	cout << mn << " " << mx << endl;
}

C++: // 最大値を求めることは簡単(一番小さい約数から淳に選べばよい)
// 最小値を求めるのはどうするか
#include <bits/stdc++.h>
using namespace std;

map<int64_t, int> prime_factor(int64_t n) {
    map<int64_t, int> ret;
    for (int64_t i = 2; i * i <= n; i++) {
        while (n % i == 0) {
            ret[i]++;
            n /= i;
        }
    }
    if (n != 1) ret[n] = 1;
    return ret;
}

int main() {
    int64_t N;
    cin >> N;
    auto p_factor = prime_factor(N);
    long long Max = 1;
    for (auto p : p_factor) {
        Max *= (p.second + 1);
    }
    --Max;
    cout << p_factor.size() << " " << Max << endl;
    return 0;
}