Problem:
Score : 1100 points

Problem Statement

We have N balance beams numbered 1 to N.
The length of each beam is 1 meters.
Snuke walks on Beam i at a speed of 1/A_i meters per second, and Ringo walks on Beam i at a speed of 1/B_i meters per second.

Snuke and Ringo will play the following game:

First, Snuke connects the N beams in any order of his choice and makes a long beam of length N meters.

Then, Snuke starts at the left end of the long beam. At the same time, Ringo starts at a point chosen uniformly at random on the long beam. Both of them walk to the right end of the long beam.

Snuke wins if and only if he catches up to Ringo before Ringo reaches the right end of the long beam. That is, Snuke wins if there is a moment when Snuke and Ringo stand at the same position, and Ringo wins otherwise.

Find the probability that Snuke wins when Snuke arranges the N beams so that the probability of his winning is maximized.

This probability is a rational number, so we ask you to represent it as an irreducible fraction P/Q (to represent 0, use P=0, Q=1).

Constraints

1 \leq N \leq 10^5

1 \leq A_i,B_i \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
A_1 B_1
A_2 B_2
\vdots
A_N B_N

Output

Print the numerator and denominator of the irreducible fraction that represents the maximum probability of Snuke's winning.

Sample Input 1

2
3 2
1 2

Sample Output 1

1 4

When the beams are connected in the order 2,1 from left to right, the probability of Snuke's winning is 1/4, which is the maximum possible value.

Sample Input 2

4
1 5
4 7
2 1
8 4

Sample Output 2

1 2

Sample Input 3

3
4 1
5 2
6 3

Sample Output 3

0 1

Sample Input 4

10
866111664 178537096
705445072 318106937
472381277 579910117
353498483 865935868
383133839 231371336
378371075 681212831
304570952 16537461
955719384 267238505
844917655 218662351
550309930 62731178

Sample Output 4

697461712 2899550585

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author majk
 */

#ifndef MAJK_LIB
#define MAJK_LIB

#include <vector>
#include <stack>
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <unordered_set>
#include <map>
#include <iomanip>
#include <set>
#include <functional>
#include <algorithm>
#include <numeric>
#include <cassert>
#include <cmath>
#include <string>
#include <queue>
#include <array>
#include <bitset>
using namespace std;

#define x first
#define y second
typedef std::pair<int,int> pii; typedef long long ll; typedef unsigned long long ull; typedef unsigned int ui; typedef pair<ui,ui> puu;

template <typename T, typename U> std::istream&operator>>(std::istream&i, pair<T,U>&p) {i >> p.x >> p.y; return i;}
template<typename T>std::istream&operator>>(std::istream&i,vector<T>&t) {for(auto&v:t){i>>v;}return i;}
template <typename T, typename U> std::ostream&operator<<(std::ostream&o, const pair<T,U>&p) {o << p.x << ' ' << p.y; return o;}
template<typename T>std::ostream&operator<<(std::ostream&o,const vector<T>&t) {if(t.empty())o<<'\n';for(size_t i=0;i<t.size();++i){o<<t[i]<<" \n"[i == t.size()-1];}return o;}
template<typename T> using minheap = priority_queue<T, vector<T>, greater<T>>;
template<typename T> using maxheap = priority_queue<T, vector<T>, less<T>>;
ui logceil(ll x) { return x?8*sizeof(ll)-__builtin_clzll(x):0; }

namespace std { template<typename T,typename U>struct hash<pair<T,U>>{hash<T>t;hash<U>u;size_t operator()(const pair<T,U>&p)const{return t(p.x)^(u(p.y)<<7);}}; }
template<typename T,typename F>T bsh(T l,T h,const F&f){T r=-1,m;while(l<=h){m=(l+h)/2;if(f(m)){l=m+1;r=m;}else{h=m-1;}}return r;}
template<typename F> double bshd(double l,double h,const F&f,double p=1e-9){ui r=3+(ui)log2((h-l)/p);while(r--){double m=(l+h)/2;if(f(m)){l=m;}else{h=m;}}return (l+h)/2;}
template<typename T,typename F>T bsl(T l,T h,const F&f){T r=-1,m;while(l<=h){m=(l+h)/2;if(f(m)){h=m-1;r=m;}else{l=m+1;}}return r;}
template<typename F> double bsld(double l,double h,const F&f,double p=1e-9){ui r=3+(ui)log2((h-l)/p);while(r--){double m=(l+h)/2;if(f(m)){h=m;}else{l=m;}}return (l+h)/2;}
template<typename T> T gcd(T a,T b) { if (a<b) swap(a,b); return b?gcd(b,a%b):a; }


template<typename T>class vector2:public vector<vector<T>>{public:vector2(){} vector2(size_t a,size_t b,T t=T()):vector<vector<T>>(a,vector<T>(b,t)){}};
template<typename T>class vector3:public vector<vector2<T>>{public:vector3(){} vector3(size_t a,size_t b,size_t c,T t=T()):vector<vector2<T>>(a,vector2<T>(b,c,t)){}};
template<typename T>class vector4:public vector<vector3<T>>{public:vector4(){} vector4(size_t a,size_t b,size_t c,size_t d,T t=T()):vector<vector3<T>>(a,vector3<T>(b,c,d,t)){}};
template<typename T>class vector5:public vector<vector4<T>>{public:vector5(){} vector5(size_t a,size_t b,size_t c,size_t d,size_t e,T t=T()):vector<vector4<T>>(a,vector4<T>(b,c,d,e,t)){}};


#endif
template<typename T> struct Fenwick {
    explicit Fenwick(ui N=0, T t=T()):N(1u<<logceil(N)),F(this->N,t),t(t){}
    explicit Fenwick(const vector<T>&A, T t=T()):N(1u<<logceil(A.size())),F(A),t(t){
        F.resize(N); fill(F.begin()+A.size(),F.end(),t);
        for(int i=0;i<N;i++){int j=i+lsb(i+1);if(j<N)F[j]+=F[i];}}
    void add(int i, T v){while(i<=N){F[i]+=v;i+=lsb(i+1);}}
    T sum(int i)const{T sum(t);while(i){sum+=F[i-1];i-=lsb(i);}return sum;}
    T range(int i,int j)const{j++; T s(t);while(j>i){s+=F[j-1];j-=lsb(j);}while(i>j){s-=F[i-1];i-=lsb(i);}return s;}
    T get(int i)const{return range(i,i);}
    void set(int i, T v) {add(i, v-get(i)); }
    constexpr int lsb(int i)const{return i&-i;}
    ui N;vector<T> F;T t;
    int max_lower(T v) {
        if (F[0] >= v) return -1;
        if (F[N-1] < v) return N-1;

        int x = 0; T a = t;
        for (int s = N>>1; s > 0; s >>= 1) if (a+F[x+s-1]<v) { a += F[x+s-1]; x += s; }
        return x;
    }
};

template<typename T> struct Fenwick2 {
    explicit Fenwick2(ui N=0, T t=T()):N(1u<<logceil(N)),F(this->N,this->N,t),t(t){}
//    explicit Fenwick2(const vector<vector<T>>&A, T t=T()):N(1u<<logceil(A.size())),F(A),t(t){
//            F.resize(N);
//            for (int i=0;i<A.size();++i) { F[i].resize(N); fill(F[i].begin()+A.size(),F[i].end(),t); }
//            for (int i=A.size();i<N;++i) { F[i].resize(N); fill(F[i].begin(),F[i].end(),t); }
//
////            for(int i=0;i<N;i++){int j=i+lsb(i+1);if(j<N)F[j]+=F[i];}
//    }
    void add(int x, int y, T v){
        while(x<=N){ int z = y; while(z<=N) { F[x][z] += v; z += lsb(z+1); }x +=lsb(x+1); }
    }

    T sum(int x, int y) {
        T sum(t);
        while (x <= N) { int z = y;while (z <= N) { sum += F[x][z];z -= lsb(z + 1); }x -= lsb(x + 1); }
        return sum;
    }
    T range(int x1, int y1, int x2, int y2) {
        T ans = sum(x2, y2);
        if (x1) ans -= sum(x1-1, y2);
        if (y1) ans -= sum(x2, y1-1);
        if (x1 && y1) ans += sum(x1-1,y1-1);
        return ans;
    }
    constexpr int lsb(int i)const{return i&-i;}
    ui N;vector2<T> F;T t;
};

class Fraction {
    friend ostream& operator<<(ostream& os, const Fraction& f);
public:
    Fraction(ll u = 0, ll v = 1) : u(u), v(v) { norm(); }
    bool operator==(const Fraction & o) const { return u == o.u && v == o.v; }
    bool operator!=(const Fraction & o) const { return u != o.u || v != o.v; }
    bool operator<(const Fraction &o) const { return u*o.v < o.u*v; }
    bool operator<=(const Fraction &o) const { return u*o.v <= o.u*v; }
    bool operator>(const Fraction &o) const { return u*o.v > o.u*v; }
    bool operator>=(const Fraction &o) const { return u*o.v >= o.u*v; }
    Fraction operator-(const Fraction& o) { return Fraction(-u, v); }
    Fraction& operator+=(const Fraction& o) { u = u * o.v + v * o.u; v *= o.v; return norm(); }
    Fraction& operator-=(const Fraction& o) { u = u * o.v - v * o.u; v *= o.v; return norm(); }
    Fraction& operator/=(const Fraction& o) { u = u * o.v; v = o.u * v; return norm(); }
    Fraction& operator*=(const Fraction& o) { u *= o.u; v *= o.v; return norm(); }
    Fraction operator+(const Fraction& o) const { Fraction f(*this); return f += o; }
    Fraction operator-(const Fraction& o) const { Fraction f(*this); return f -= o; }
    Fraction operator*(const Fraction& o) const { Fraction f(*this); return f *= o; }
    Fraction operator/(const Fraction& o) const { Fraction f(*this); return f /= o; }

    Fraction& norm() {
        ll g = gcd(abs(u),abs(v));
        u /= g;
        v /= g;
        if (v < 0) {
            u = -u;
            v = -v;
        }
        return *this;
    }

    ll u,v;
};


ostream& operator<<(ostream& os, const Fraction& f) {
    os << f.u << '/' << f.v;
    return os;
}
#ifndef MAJK_INT128_H
#define MAJK_INT128_H


/** Product of two 64-bit numbers modulo another. */
ull mulull(ull a, ull z, ull mod) {
#ifdef __SIZEOF_INT128__
    __int128 result = ((__int128) a * (__int128) z) % (__int128) mod;
    return (ull) result;
#else
    // schrage method
	ull q = mod / a, r = mod % a;
	ull rzq = (r < q) ? r * (z/q) : mulull(r, z/q, mod);
	ull azq = a * (z % q);
	if (azq >= rzq) return azq-rzq; else return azq-rzq+mod;
#endif
}

/** Multiply two 64-bit unsigned integers to get a 128-bit unsigned integer (as a pair of ull) */
pair<ull,ull> mulull(ull a, ull b) {
#ifdef __SIZEOF_INT128__
    __int128 result = (__int128) a * (__int128) b;
    return {(ull) (result >> 64), (ull) result};
#else
    ull c = (ui)a, d = a>>32, e = (ui)b, f = b>>32, g = d*f, h = d*e, i = f*c, j = c*e, k = (j>>32)+(ui)h+(ui)i, left = g+(h>>32)+(i>>32)+(k>>32);
	return {left, ((h+i) << 32) + j};
#endif
}


bool fractionGreaterOrEqual(ll a, ll b, ll c, ll d) {
    if (b < 0) { b = -b; a = -a; }
    if (d < 0) { d = -d; c = -c; }
    return a < 0 && c < 0 ? mulull(-a, d) <= mulull(-c, b) : (a >= 0) && (c < 0 || mulull(a, d) >= mulull(c, b));
}

bool fractionGreaterOrEqual(pair<ll, ll> a, pair<ll, ll> b) {
    return fractionGreaterOrEqual(a.x, a.y, b.x, b.y);
}


bool fractionGreaterOrEqual(double a, double b, double c, double d) {
    return a/b >= c/d;
}

// this is based on modulus, but it's 2-3 times slower than the former
//bool fractionGreaterOrEqual(ll a, ll b, ll c, ll d) {
//	if (a<0 && c<0) return greaterOrEqual(-c,d,-a,b);
//	if (a<0) return false;
//	if (c<0) return true;
//	if (b==0) return true;
//	if (d==0) return false;
//	ll ab = a/b, cd = c/d;
//	if (ab > cd) return true;
//	if (ab < cd) return false;
//	return !greaterOrEqual(b, a%b, d, c%d);
//}

#endif //MAJK_INT128_H

typedef pair<ll,ll> pll;
class DBalanceBeam {
public:
    void solve(istream& cin, ostream& cout) {
        int N; cin >> N;
        vector<pll> B(N); cin >> B;
        sort(B.begin(),B.end(),[](pll a, pll b) { return a.y > b.y || (a.y == b.y && a.x > b.x); });
        Fenwick<ll> BSum(N, 0LL);
        Fenwick<ll> Cnt(N, 0);
        ll good = 0;
        vector<pair<pll, int>> Bad;
        for (int i = 0; i < N; ++i) {
            if (B[i].x <= B[i].y) {
                good += B[i].x;
                Cnt.add(i, 1);
                BSum.add(i, B[i].y);
            } else {
                Bad.push_back({B[i], i});
            }
        }

        ll bestNum = 0, bestDen = 1;
        sort(Bad.begin(),Bad.end(), [&](pair<pll,int> a, pair<pll,int> b) { return a.x.x < b.x.x; });
        for (int i = 0; i <= Bad.size(); ++i) {
            int x = bsh(0, N-1, [&](int j) { return BSum.range(0, j) <= good; });//BSum.max_lower(good);

            int left = x == -1 ? 0 : Cnt.sum(x+1);
            ll tot = x == -1 ? 0LL : BSum.sum(x+1);

            if (x != N-1) {
                ll num = (Cnt.sum(N) - left) * ll(B[x+1].y) - (good - tot);
                ll den = B[x+1].y;

                if (fractionGreaterOrEqual(num, den, bestNum, bestDen)) {
                    bestNum = num;
                    bestDen = den;
                }
            } else {
                ll num = (Cnt.sum(N) - left);
                ll den = 1;
                if (fractionGreaterOrEqual(num, den, bestNum, bestDen)) {
                    bestNum = num;
                    bestDen = den;
                }
            }

            if (i != Bad.size()) {
                Cnt.add(Bad[i].y, 1);
                BSum.add(Bad[i].y, Bad[i].x.y);
                good += Bad[i].x.x;
            }
        }

        bestDen *= N;
        ll g = gcd(bestNum, bestDen);
        cout << bestNum/g << ' ' << bestDen/g << '\n';
    }
};


int main() {
	ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
	DBalanceBeam solver;
	std::istream& in(std::cin);
	std::ostream& out(std::cout);
	solver.solve(in, out);
    return 0;
}