#include<bits/stdc++.h>
using namespace std;

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define reps(i,a,b) for(int i=(a);i<(b);i++)
#define pb push_back
#define eb emplace_back
#define all(v) (v).begin(),(v).end()
#define fi first
#define se second

using vint=vector<int>;
using pint=pair<int,int>;
using vpint=vector<pint>;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

template<class A,class B>
ostream& operator<<(ostream& ost,const pair<A,B>&p){
    ost<<"{"<<p.first<<","<<p.second<<"}";
    return ost;
}

template<class T>
ostream& operator<<(ostream& ost,const vector<T>&v){
    ost<<"{";
    for(int i=0;i<v.size();i++){
        if(i)ost<<",";
        ost<<v[i];
    }
    ost<<"}";
    return ost;
}

struct Fraction{
    int64_t gcd(int64_t a,int64_t b){
        return b?gcd(b,a%b):a;
    }
	int64_t a,b;
	Fraction():a(0),b(1){}
	Fraction(int64_t a):a(a),b(1){}
	Fraction(int64_t a,int64_t b):a(a),b(b){
		if(b<0)a*=-1,b*=-1;
        int64_t g=gcd((a>0?a:-a),b);
        a/=g;
        b/=g;
    }
	bool operator==(const Fraction& f)const{return a==f.a&&b==f.b;}
	bool operator!=(const Fraction& f)const{return a!=f.a||b!=f.b;}
	Fraction& operator+=(const Fraction& f){
		int64_t c=a*f.b+b*f.a;
		int64_t d=b*f.b;
		int64_t g=gcd((c>0?c:-c),d);
		a=c/g;
		b=d/g;
		return *this;
	}
	Fraction& operator-=(const Fraction& f){
		int64_t c=a*f.b-b*f.a;
		int64_t d=b*f.b;
		int64_t g=gcd((c>0?c:-c),d);
		a=c/g;
		b=d/g;
		return *this;
	}
	Fraction& operator*=(const Fraction& f){
		int64_t c=a*f.a;
		int64_t d=b*f.b;
		int64_t g=gcd((c>0?c:-c),d);
		a=c/g;
		b=d/g;
		return *this;
	}
	Fraction& operator/=(const Fraction& f){
		int64_t c=a*f.b;
		int64_t d=b*f.a;
		if(d<0)c*=-1,d*=-1;
		int64_t g=gcd((c>0?c:-c),d);
		a=c/g;
		b=d/g;
		return *this;
	}
	Fraction operator+(const Fraction& f)const{return Fraction(*this)+=f;}
	Fraction operator-(const Fraction& f)const{return Fraction(*this)-=f;}
	Fraction operator*(const Fraction& f)const{return Fraction(*this)*=f;}
	Fraction operator/(const Fraction& f)const{return Fraction(*this)/=f;}
	bool operator<(const Fraction& f)const{return (Fraction(*this)-f).a<0;}
	bool operator>(const Fraction& f)const{return (Fraction(*this)-f).a>0;}
	bool operator<=(const Fraction& f)const{return (Fraction(*this)-f).a<=0;}
	bool operator>=(const Fraction& f)const{return (Fraction(*this)-f).a>=0;}
	Fraction operator+()const{return Fraction(*this);}
	Fraction operator-()const{return Fraction()-Fraction(*this);}
};



signed main(){
    int N;
    scanf("%lld",&N);

    map<int,vint>bucket;
    int cap=0;
    rep(i,N){
        int a,b;
        scanf("%lld%lld",&a,&b);
        if(a<=b){
            cap+=b-a;
            bucket[b].pb(b);
        }
        else{
            bucket[b].pb(a);
        }
    }

    Fraction ans;
    priority_queue<int>que;
    int sum=0;

    for(auto &uku:bucket){
        int b=uku.first;
        vint &lis=uku.second;

        sort(all(lis));
        for(auto u:lis){
            if(sum+u<=cap){
                sum+=u;
                que.push(u);
                continue;
            }

            if(u==b){
                chmax(ans,Fraction(cap-sum,b)+que.size());
            }
            else if(cap+(b-u)-sum>=0){
                chmax(ans,Fraction(cap+b-u-sum,b)+que.size());
            }
            que.push(u);
            sum+=u;
            sum-=que.top();
            que.pop();
        }
    }
    ans/=N;
    cout<<ans.a<<" "<<ans.b<<endl;
    return 0;
}

Measured memory_bytes: 11900