#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL
    #define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
    #define eprintf(...) 42
#endif

using ll = long long;
using ld = long double;
using D = double;
using uint = unsigned int;
template<typename T>
using pair2 = pair<T, T>;
using pii = pair<int, int>;
using pli = pair<ll, int>;
using pll = pair<ll, ll>;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second

#ifdef LOCAL
__int128 abs(__int128 a)
{
	return a > 0 ? a : -a;
}
#endif

__int128 gcd(__int128 a, __int128 b)
{
	return a == 0 ? b : gcd(b % a, a);
}

struct frac
{
	__int128 up, down;
	
	frac() {}
	frac(__int128 up_, __int128 down_)
	{
		up = up_;
		down = down_;
		
		__int128 g = gcd(abs(up), abs(down));
		up /= g;
		down /= g;
		if (down < 0)
		{
			up *= -1;
			down *= -1;
		}
	}
};

inline frac operator+(const frac &a, const frac &b)
{
	return frac(a.up * b.down + a.down * b.up, a.down * b.down);
}

inline bool operator<(const frac &a, const frac &b)
{
	return a.up * b.down < b.up * a.down;
}

const int maxn = 100005;
const ll inf = 1e18;

vector<pair2<int>> fast, slow;
ll sumbfast[maxn];
int n;
ll totald;
int curpos = 0;
priority_queue<ll> take;
priority_queue<ll, vector<ll>, greater<ll>> nottake;
int ntake;
ll sumB;


void add(ll tA, ll tB)
{
	totald += tA - tB;
	
	if (!take.empty() && tB < take.top())
	{
		take.push(tB);
		//cout << "take " << tB << endl;
		ntake++;
		sumB += tB;
	} else
	{
		nottake.push(tB);
	}
}

frac solvefast()
{
	while (!nottake.empty() && sumB < -totald)
	{
		ll x = nottake.top();
		//cout << "take " << x << endl;
		nottake.pop();
		sumB += x;
		ntake++;
		take.push(x);
	}
	while (!take.empty() && sumB - take.top() >= -totald)
	{
		ll x = take.top();
		//cout << "untake " << x << endl;
		take.pop();
		sumB -= x;
		ntake--;
		nottake.push(x);
	}
	if (take.empty()) return frac(0, 1);
	frac curans = frac(ntake - 1, n);
	ll up = min(take.top(), -totald - (sumB - take.top()));
	//cout << -totald << endl;
	//cout << "here " << ntake << ' ' << sumB << ' ' << up << ' ' << take.top() << endl;
	return curans + frac(up, n * take.top());
}

int main()
{
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		if (x <= y) fast.pb({x, y});
		else slow.pb({x, y});
	}
	sort(all(fast), [&] (pair2<int> &a, pair2<int> &b) {return a.se < b.se; });

	sort(all(slow), [&] (pair2<int> &a, pair2<int> &b) {return a.fi < b.fi; });
	
	totald = 0;
	for (auto t : fast) add(t.fi, t.se);
	

	ll tB = 0;
	ll tA = 0;
	frac answer = solvefast();
	for (int i = 0; i < (int)slow.size(); i++)
	{
		//cout << i << ' ' << (ll)answer.up << ' ' << (ll)answer.down << endl;
		add(slow[i].fi, slow[i].se);
		tA += slow[i].fi;
		tB += slow[i].se;
		answer = max(answer, solvefast());
	}
	printf("%lld %lld\n", (ll)answer.up, (ll)answer.down);
    return 0;
}
