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 Egor Kulikov
 */

#include <iostream>
#include <fstream>

#include <bits/stdc++.h>
//
// Created by kulikov on 10/17/2019.
//

#ifndef JHELPER_EXAMPLE_PROJECT_INPUT_H
#define JHELPER_EXAMPLE_PROJECT_INPUT_H

//
// Created by egor on 30.10.2019.
//

#ifndef JHELPER_EXAMPLE_PROJECT_GENERAL_H
#define JHELPER_EXAMPLE_PROJECT_GENERAL_H



using namespace std;

typedef long long longint;
typedef vector<int> vi;
typedef pair<int, int> pii;

const int MAX_INT = 2147483647;

const double PI = atan(1) * 4;

const int DX_KNIGHT[] = {2, 1, -1, -2, -2, -1, 1, 2};
const int DY_KNIGHT[] = {1, 2, 2, 1, -1, -2, -2, -1};
const int DX4[] = {1, 0, -1, 0};
const int DY4[] = {0, 1, 0, -1};

bool isValidCell(int x, int y, int rows, int cols) {
    return x >= 0 && y >= 0 && x < rows && y < cols;
}

void decreaseByOne() {
}

template <typename T, class...Vargs>
void decreaseByOne(vector<T>& arr, Vargs...arrs) {
    for (int& i : arr) {
        i--;
    }
    decreaseByOne(arrs...);
}

#endif //JHELPER_EXAMPLE_PROJECT_GENERAL_H


class Input {
public:
    enum ErrorType {
        OK,
        END_OF_FILE,
        UNEXPECTED_SYMBOL,
        INVALID_CALL
    };

private:
    istream& in;
    bool exhausted = false;
    ErrorType error = OK;
    int get();
    template<typename T> T readInteger();
    int skipWhitespace();

public:
    Input(istream& in);
    int readInt();
    longint readLong();
    string readString();
    vector<int> readIntArray(int size);
    template<typename T> T readType();
    template<typename T, typename U> pair<T, U> readType();
    template<typename T> vector<T> readArray(int size);
    template<typename T1, typename T2> tuple<vector<T1>, vector<T2> > readArrays(int size);
    template<typename T1, typename T2, typename T3> tuple<vector<T1>, vector<T2>, vector<T3> > readArrays(int size);
    template<typename T1, typename T2, typename T3, typename T4>
        tuple<vector<T1>, vector<T2>, vector<T3>, vector<T4> > readArrays(int size);
    template<typename T1, typename T2, typename T3, typename T4, typename T5>
        tuple<vector<T1>, vector<T2>, vector<T3>, vector<T4>, vector<T5> > readArrays(int size);
    template<typename T> vector<vector<T> > readTable(int rows, int cols);

    string readLine();
};

inline bool isWhitespace(int c) {
    return isspace(c) || c == EOF;
}

int Input::skipWhitespace() {
    int c;
    do {
        c = get();
        if (exhausted) {
            error = END_OF_FILE;
            return c;
        }
    } while (isWhitespace(c));
    return c;
}

Input::Input(std::istream &in) : in(in) {
}

inline int Input::get() {
    int result = in.get();
    if (result == EOF) {
        exhausted = true;
    }
    return result;
}

template<typename T>
T Input::readType() {
    error = INVALID_CALL;
    return nullptr;
}

template<typename T>
T Input::readInteger() {
    error = OK;
    int c = skipWhitespace();
    if (error != OK) {
        return 0;
    }
    int sgn = 1;
    if (c == '-') {
        sgn = -1;
        c = get();
    }
    T res = 0;
    do {
        if (!isdigit(c)) {
            error = UNEXPECTED_SYMBOL;
            return 0;
        }
        res *= 10;
        res += c - '0';
        c = get();
    } while (!isWhitespace(c));
    return res * sgn;
}

template<>
int Input::readType() {
    return readInteger<int>();
}

template<>
longint Input::readType() {
    return readInteger<longint>();
}

template<>
char Input::readType() {
    error = OK;
    int c = skipWhitespace();
    if (error != OK) {
        return 0;
    }
    return c;
}

template<>
string Input::readType() {
    error = OK;
    int c = skipWhitespace();
    if (error != OK) {
        return "";
    }
    vector<char> res;
    do {
        if (error != OK) {
            return "";
        }
        res.push_back(c);
    } while (!isWhitespace(c = get()));
    return string(res.begin(), res.end());
}

inline int Input::readInt() {
    return readType<int>();
}

inline longint Input::readLong() {
    return readType<longint>();
}

template<typename T>
vector<T> Input::readArray(int size) {
    vector<T> res;
    res.reserve(size);
    for (int i = 0; i < size; i++) {
        res.push_back(readType<T>());
        if (error != OK) {
            res.clear();
            return res;
        }
    }
    return res;
}

vector<int> Input::readIntArray(int size) {
    return readArray<int>(size);
}

template<typename T1, typename T2>
tuple<vector<T1>, vector<T2> > Input::readArrays(int size) {
    vector<T1> v1;
    vector<T2> v2;
    v1.reserve(size);
    v2.reserve(size);
    for (int i = 0; i < size; ++i) {
        v1.push_back(readType<T1>());
        v2.push_back(readType<T2>());
    }
    return make_tuple(v1, v2);
}

string Input::readString() {
    return readType<string>();
}

template<typename T>
vector<vector<T>> Input::readTable(int rows, int cols) {
    vector<vector<T> > result;
    result.reserve(rows);
    for (int i = 0; i < rows; ++i) {
        result.push_back(readArray<T>(cols));
    }
    return result;
}

string Input::readLine() {
    error = OK;
    int c = skipWhitespace();
    if (error != OK) {
        return "";
    }
    int length = 0;
    vector<char> res;
    do {
        if (error != OK) {
            return "";
        }
        res.push_back(c);
        if (!isWhitespace(c)) {
            length = res.size();
        }
        c = get();
    } while (c != '\n' && c != '\r' && c != EOF);
    return string(res.begin(), res.begin() + length);
}

template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3> > Input::readArrays(int size) {
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    v1.reserve(size);
    v2.reserve(size);
    v3.reserve(size);
    for (int i = 0; i < size; ++i) {
        v1.push_back(readType<T1>());
        v2.push_back(readType<T2>());
        v3.push_back(readType<T3>());
    }
    return make_tuple(v1, v2, v3);
}

template<typename T1, typename T2, typename T3, typename T4>
tuple<vector<T1>, vector<T2>, vector<T3>, vector<T4> > Input::readArrays(int size) {
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    vector<T4> v4;
    v1.reserve(size);
    v2.reserve(size);
    v3.reserve(size);
    v4.reserve(size);
    for (int i = 0; i < size; ++i) {
        v1.push_back(readType<T1>());
        v2.push_back(readType<T2>());
        v3.push_back(readType<T3>());
        v4.push_back(readType<T4>());
    }
    return make_tuple(v1, v2, v3, v4);
}

template<typename T1, typename T2, typename T3, typename T4, typename T5>
tuple<vector<T1>, vector<T2>, vector<T3>, vector<T4>, vector<T5> > Input::readArrays(int size) {
    vector<T1> v1;
    vector<T2> v2;
    vector<T3> v3;
    vector<T4> v4;
    vector<T5> v5;
    v1.reserve(size);
    v2.reserve(size);
    v3.reserve(size);
    v4.reserve(size);
    v5.reserve(size);
    for (int i = 0; i < size; ++i) {
        v1.push_back(readType<T1>());
        v2.push_back(readType<T2>());
        v3.push_back(readType<T3>());
        v4.push_back(readType<T4>());
        v5.push_back(readType<T5>());
    }
    return make_tuple(v1, v2, v3, v4, v5);
}

#endif //JHELPER_EXAMPLE_PROJECT_INPUT_H

//
// Created by egor on 31.10.2019.
//

#ifndef JHELPER_EXAMPLE_PROJECT_OUTPUT_H
#define JHELPER_EXAMPLE_PROJECT_OUTPUT_H



class Output {
private:
    ostream& out;
    template<typename T> void printSingle(const T& value);
    template<typename T> void printSingle(const vector<T>& value);
    template<typename T, typename U> void printSingle(const pair<T, U>& value);

public:
    Output(ostream& out);
    void print();
    template<typename T, typename...Targs>void print(const T& first, const Targs... args);
    template<typename...Targs>void printLine(const Targs... args);
    void flush();
};

Output::Output(ostream &out) : out(out) {
    out << setprecision(12);
}

void Output::print() {
}

template<typename T, typename... Targs>
void Output::print(const T& first, const Targs... args) {
    printSingle(first);
    if (sizeof...(args) != 0) {
        out << ' ';
        print(args...);
    }
}

template<typename T>
void Output::printSingle(const T& value) {
    out << value;
}

template<typename... Targs>
void Output::printLine(const Targs... args) {
    print(args...);
    out << '\n';
}

void Output::flush() {
    out.flush();
}

template<typename T>
void Output::printSingle(const vector<T>& array) {
    unsigned int size = array.size();
    for (int i = 0; i < size; ++i) {
        out << array[i];
        if (i + 1 != size) {
            out << ' ';
        }
    }
}

template<typename T, typename U>
void Output::printSingle(const pair<T, U>& value) {
    out << value.first << ' ' << value.second;
}

#endif //JHELPER_EXAMPLE_PROJECT_OUTPUT_H

//
// Created by egor on 31.10.2019.
//

#ifndef JHELPER_EXAMPLE_PROJECT_ALGO_H
#define JHELPER_EXAMPLE_PROJECT_ALGO_H



template <class V>
inline void sort(V& v) {
    sort(v.begin(), v.end());
}

template <typename T, class C>
inline void sort(vector<T>& v, C c) {
    sort(v.begin(), v.end(), c);
}

template <typename T>
inline void unique(vector<T>& v) {
    v.resize(unique(v.begin(), v.end()) - v.begin());
}

template <typename T>
inline T accumulate(const vector<T>& v) {
    return accumulate(v.begin(), v.end(), T(0));
}

vi createOrder(int n) {
    vi order(n);
    for (int i = 0; i < n; i++) {
        order[i] = i;
    }
    return order;
}

template <typename T>
inline void reverse(vector<T>& v) {
    reverse(v.begin(), v.end());
}

template <typename T>
inline T minElement(const vector<T>& v) {
    return *min_element(v.begin(), v.end());
}

template <typename T>
inline T maxElement(const vector<T>& v) {
    return *max_element(v.begin(), v.end());
}

template <typename T>
inline vector<vector<T> > makeArray(int a, int b) {
    return vector<vector<T> >(a, vector<T>(b));
}

template <typename T>
inline vector<vector<vector<T> > > makeArray(int a, int b, int c) {
    return vector<vector<vector<T> > >(a, makeArray<T>(b, c));
}

template <typename T>
inline vector<vector<T> > makeArray(int a, int b, T init) {
    return vector<vector<T> >(a, vector<T>(b, init));
}

template <typename T>
inline vector<vector<vector<T> > > makeArray(int a, int b, int c, T init) {
    return vector<vector<vector<T> > >(a, makeArray<T>(b, c, init));
}

template <typename T>
inline void addAll(vector<T>& v, const vector<T>& toAdd) {
    v.insert(v.end(), toAdd.begin(), toAdd.end());
}

template <typename T>
inline void fill(vector<T>& v, const T& val) {
    fill(v.begin(), v.end(), val);
}

#endif //JHELPER_EXAMPLE_PROJECT_ALGO_H

//
// Created by egor on 01.11.2019.
//

#ifndef JHELPER_EXAMPLE_PROJECT_NUMBERS_H
#define JHELPER_EXAMPLE_PROJECT_NUMBERS_H


//
// Created by egor on 31.10.2019.
//

#ifndef JHELPER_EXAMPLE_PROJECT_MODULO_H
#define JHELPER_EXAMPLE_PROJECT_MODULO_H



const int MOD7 = 1000000007;
const int MOD9 = 1000000009;
const int MODF = 998244353;

int mod = MOD7;

class ModuloInt {
private:
    longint n;

public:
    ModuloInt() : n(0) {}
    ModuloInt(int n) {
        n %= mod;
        if (n < 0) {
            n += mod;
        }
        this->n = n;
    }
    ModuloInt(const ModuloInt& n) = default;
    ModuloInt& operator +=(const ModuloInt& other);
    ModuloInt& operator -=(const ModuloInt& other);
    ModuloInt& operator *=(const ModuloInt& other);
    ModuloInt operator -();
    friend ostream&operator <<(ostream& out, const ModuloInt& val);
};

ModuloInt &ModuloInt::operator+=(const ModuloInt& other) {
    n += other.n;
    if (n >= mod) {
        n -= mod;
    }
    return *this;
}

ModuloInt &ModuloInt::operator-=(const ModuloInt& other) {
    n -= other.n;
    if (n < 0) {
        n += mod;
    }
    return *this;
}

ModuloInt &ModuloInt::operator*=(const ModuloInt& other) {
    n *= other.n;
    n %= mod;
    return *this;
}

ModuloInt operator +(const ModuloInt& a, const ModuloInt& b) {
    return ModuloInt(a) += b;
}

ModuloInt operator -(const ModuloInt& a, const ModuloInt& b) {
    return ModuloInt(a) -= b;
}

ModuloInt operator *(const ModuloInt& a, const ModuloInt& b) {
    return ModuloInt(a) *= b;
}

ostream& operator <<(ostream& out, const ModuloInt& val) {
    return out << val.n;
}

ModuloInt ModuloInt::operator-() {
    if (n == 0) {
        return 0;
    }
    return ModuloInt(mod - n);
}

#endif //JHELPER_EXAMPLE_PROJECT_MODULO_H


template <typename T>
T gcd(T a, T b) {
    a = abs(a);
    b = abs(b);
    while (b != 0) {
        a = a % b;
        swap(a, b);
    }
    return a;
}

template <typename T>
T power(const T& a, longint b) {
    if (b == 0) {
        return 1;
    }
    if ((b & 1) == 0) {
        T res = power(a, b >> 1);
        return res * res;
    } else {
        return power(a, b - 1) * a;
    }
}

template <typename T>
vector<T> generateFactorial(int length) {
    vector<T> result(length);
    if (length > 0) {
        result[0] = 1;
    }
    for (int i = 1; i < length; i++) {
        result[i] = result[i - 1] * i;
    }
    return result;
}

template <typename T>
vector<T> generateReverse(int length) {
    vector<T> result(length);
    if (length > 1) {
        result[1] = 1;
    }
    for (int i = 2; i < length; i++) {
        result[i] = -(mod / i) * result[mod % i];
    }
    return result;
}

template <typename T>
vector<T> generatePowers(T base, int length) {
    vector<T> result(length);
    if (length > 0) {
        result[0] = 1;
    }
    for (int i = 1; i < length; i++) {
        result[i] = result[i - 1] * base;
    }
    return result;
}

template <typename T>
vector<T> generateReverseFactorial(int length) {
    auto result = generateReverse<T>(length);
    if (length > 0) {
        result[0] = 1;
    }
    for (int i = 1; i < length; i++) {
        result[i] *= result[i - 1];
    }
    return result;
}

template <typename T>
class Combinations {
private:
    vector<T> fact;
    vector<T> revFactorial;

public:
    Combinations(int length) {
        fact = generateFactorial<T>(length);
        revFactorial = generateReverseFactorial<T>(length);
    }

public:
    T c(int n, int k) {
        if (k < 0 || k > n) {
            return 0;
        }
        return fact[n] * revFactorial[k] * revFactorial[n - k];
    }

    T factorial(int n) {
        return fact[n];
    }

    T reverseFactorial(int n) {
        return revFactorial[n];
    }
};

#endif //JHELPER_EXAMPLE_PROJECT_NUMBERS_H


using namespace std;

class DBalanceBeam {
public:
	void solve(std::istream& inp, std::ostream& outp) {
        Input in(inp);
        Output out(outp);

        int n = in.readInt();
        vector<pair<longint, longint> > beams(n);
        for (int i = 0; i < n; ++i) {
            longint a = in.readInt();
            longint b = in.readInt();
            beams[i] = make_pair(a, b);
        }
        longint delta = 0;
        vector<pair<longint, longint> > bad;
        multiset<longint, greater<longint> > take;
        longint sum = 0;
        for (const auto& p : beams) {
            if (p.first <= p.second) {
                delta += p.second - p.first;
                take.insert(p.second);
                sum += p.second;
            } else {
                bad.push_back(p);
            }
        }
        if (take.empty() || delta == 0) {
            out.printLine(0, 1);
            return;
        }
        while (sum >= delta + *take.begin()) {
            sum -= *take.begin();
            take.erase(take.begin());
        }
        longint last = *take.begin();
        longint remaining = last - (sum - delta);
        sort(bad, [](const pair<longint, longint>& x, const pair<longint, longint>& y) -> bool {if (x.first != y.first) {return x.first < y.first;} return x.second > y.second;});
        for (const auto& p : bad) {
            longint a = p.first;
            if (last <= a) {
                break;
            }
            if (remaining >= a) {
                remaining -= a;
                take.insert(p.second);
                continue;
            }
            longint wasLast = last;
            longint wasRemaining = remaining;
            take.erase(take.begin());
            take.insert(p.second);
            longint newLast = *take.begin();
            longint need = a - remaining;
            if (longint(need) * wasLast + longint(newLast) * wasRemaining < longint(newLast) * wasLast) {
                last = newLast;
                remaining = last - need;
            } else {
                take.erase(take.find(p.second));
                take.insert(wasLast);
                remaining = wasRemaining;
                last = wasLast;
                break;
            }
        }
        longint p = longint(take.size() - 1) * last + remaining;
        longint q = longint(last) * n;
        longint g = gcd(p, q);
        p /= g;
        q /= g;
        out.printLine(p, q);
	}
};


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