Problem:
Score : 500 points

Problem Statement

An adult game master and N children are playing a game on an ice rink.
The game consists of K rounds.
In the i-th round, the game master announces:

Form groups consisting of A_i children each!

Then the children who are still in the game form as many groups of A_i children as possible.
One child may belong to at most one group.
Those who are left without a group leave the game. The others proceed to the next round.
Note that it's possible that nobody leaves the game in some round.

In the end, after the K-th round, there are exactly two children left, and they are declared the winners.

You have heard the values of A_1, A_2, ..., A_K. You don't know N, but you want to estimate it.

Find the smallest and the largest possible number of children in the game before the start, or determine that no valid values of N exist.

Constraints

1 \leq K \leq 10^5

2 \leq A_i \leq 10^9

All input values are integers.

Input

Input is given from Standard Input in the following format:

K
A_1 A_2 ... A_K

Output

Print two integers representing the smallest and the largest possible value of N, respectively,
or a single integer -1 if the described situation is impossible.

Sample Input 1

4
3 4 3 2

Sample Output 1

6 8

For example, if the game starts with 6 children, then it proceeds as follows:

In the first round, 6 children form 2 groups of 3 children, and nobody leaves the game.

In the second round, 6 children form 1 group of 4 children, and 2 children leave the game.

In the third round, 4 children form 1 group of 3 children, and 1 child leaves the game.

In the fourth round, 3 children form 1 group of 2 children, and 1 child leaves the game.

The last 2 children are declared the winners.

Sample Input 2

5
3 4 100 3 2

Sample Output 2

-1

This situation is impossible.
In particular, if the game starts with less than 100 children, everyone leaves after the third round.

Sample Input 3

10
2 2 2 2 2 2 2 2 2 2

Sample Output 3

2 3

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
//using System.Data.Odbc;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Proxies;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Schema;
namespace ConsoleApplication
{
    class MainClass
    {
        ////////////////////////////////////////////////////////////////////////////////        
        int K;
        long[] A;
        void Solve() {
            io.i(out K);
            io.ini(out A, K);
            long min = 2L;
            long max = 2L;
            var hoge = A.Reverse().ToArray();
            if (hoge[0] != 2) {
                io.o(-1);
                return;
            }
            var rmin = hoge[0];
            var rmax = hoge[0];

            Func<long, long, long, long> f1 = (n, start, fin) =>
                (start + n - 1) / n;

            Func<long, long, long, long> f2 = (n, start, fin) =>
                fin / n;

            for (int i = 0; i < K; ++i) {
                //io.o("call " + i);
                var ff1 = f1(hoge[i], rmin, rmax);
                var ff2 = f2(hoge[i], rmin, rmax);
                if (ff1 > ff2) {
                    io.o(-1);
                    return;
                }
                rmin = hoge[i] * ff1;
                rmax = hoge[i] * (ff2 + 1) - 1;
            }

            io.ol(rmin, rmax);

        }


        ////////////////////////////////////////////////////////////////////////////////
        public static void Main() => new MainClass().Stream();
        IO io = new IO();
        Mat mat = new Mat();
        void Stream() {
            Solve();
            //Test();
            io.Flush();
        }
        void Test() {

        }
        void FOR(int a, int b, Action<int> act) {
            for (int i = a; i < b; ++i) act(i);
        }
        void FORR(int a, int b, Action<int> act) {
            for (int i = a - 1; i >= b; --i) act(i);
        }
    }
    #region Default
    class IO
    {
        #region INPUT
        int _buffCnt;
        string[] _nextBuff;
        private readonly char[] _splitCharacter = new char[] { ' ' };
        private readonly StreamWriter _sw = new StreamWriter(Console.OpenStandardOutput()) {
            AutoFlush = false
        };
        public IO() {
            _nextBuff = new string[0];
            _buffCnt = 0;
            Console.SetOut(_sw);
        }
        private string Next() {
            if (_buffCnt < _nextBuff.Length) return _nextBuff[_buffCnt++];
            var str = Scan;
            while (str == "") str = Scan;
            _nextBuff = str.Split(_splitCharacter, StringSplitOptions.RemoveEmptyEntries);
            _buffCnt = 0;
            return _nextBuff[_buffCnt++];
        }
        private string Scan => Console.ReadLine();
        private string[] Arr => Scan.Split(' ');
        private void Read<T>(out T v) => v = SuitType<T>(Next());
        private T ConvertType<T, TU>(TU v) => (T)Convert.ChangeType(v, typeof(T));
        private bool TypeEqual<T, TU>() => typeof(T) == typeof(TU);
        private T SuitType<T>(string s)
            =>
                TypeEqual<T, int>()
                    ? ConvertType<T, int>(int.Parse(s))
                    : TypeEqual<T, long>()
                        ? ConvertType<T, long>(long.Parse(s))
                        : TypeEqual<T, double>()
                            ? ConvertType<T, double>(double.Parse(s))
                            : TypeEqual<T, char>() ? ConvertType<T, char>(char.Parse(s)) : ConvertType<T, string>(s);
        public string String => Next();
        public char Char => char.Parse(Next());
        public int Int => int.Parse(Next());
        public long Long => long.Parse(Next());
        public double Double => double.Parse(Next());
        public string[] ArrString => Arr;
        public char[] ArrChar => Array.ConvertAll(Arr, char.Parse);
        public int[] ArrInt => Array.ConvertAll(Arr, int.Parse);
        public long[] ArrLong => Array.ConvertAll(Arr, long.Parse);
        public double[] ArrDouble => Array.ConvertAll(Arr, double.Parse);
        public void Flush() => Console.Out.Flush();
        private T i<T>() { return SuitType<T>(String); }
        public void i<T>(out T v) => Read(out v);
        public void i<T, TU>(out T t, out TU u) {
            i(out t);
            i(out u);
        }
        public void i<T, TU, TV>(out T t, out TU u, out TV v) {
            i(out t, out u);
            i(out v);
        }
        public void i<T, TU, TV, TW>(out T t, out TU u, out TV v, out TW w) {
            i(out t, out u, out v);
            i(out w);
        }
        public void i<T, TU, TV, TW, TX>(out T t, out TU u, out TV v, out TW w, out TX x) {
            i(out t, out u, out v, out w);
            i(out x);
        }
        public void ini<T>(out T[] a, int n) {
            a = new T[n];
            for (int i = 0; i < n; ++i) a[i] = i<T>();
        }
        public void ini<T, TU>(out T[] a, out TU[] b, int n) {
            a = new T[n];
            b = new TU[n];
            for (int i = 0; i < n; ++i) {
                a[i] = i<T>();
                b[i] = i<TU>();
            }
        }
        public void ini<T, TU, TV>(out T[] a, out TU[] b, out TV[] c, int n) {
            a = new T[n];
            b = new TU[n];
            c = new TV[n];
            for (int i = 0; i < n; ++i) {
                a[i] = i<T>();
                b[i] = i<TU>();
                c[i] = i<TV>();
            }
        }
        public void ini<T>(out T[,] a, int h, int w) {
            a = new T[h, w];
            for (int i = 0; i < h; ++i) for (int j = 0; j < w; ++j) a[i, j] = i<T>();
        }
        public void ini<T, TU>(out Tuple<T, TU>[] t, int n) {
            t = new Tuple<T, TU>[n];
            for (int j = 0; j < n; ++j) {
                T i1;
                TU i2;
                i(out i1, out i2);
                t[j] = Tuple.Create(i1, i2);
            }
        }
        public void ini<T, TU, TV>(out Tuple<T, TU, TV>[] t, int n) {
            t = new Tuple<T, TU, TV>[n];
            for (int j = 0; j < n; ++j) {
                T i1;
                TU i2;
                TV i3;
                i(out i1, out i2, out i3);
                t[j] = Tuple.Create(i1, i2, i3);
            }
        }
        #endregion
        #region OUTPUT
        private void Out<T>(T v) => Console.Write(v);
        private void OutLine<T>(T v) => Console.WriteLine(v);
        public void o<T>(T v) => OutLine(v);
        public void o<T>(params T[] a) => Array.ForEach(a, OutLine);
        public void o<T>(T[,] a) {
            int a0 = a.GetLength(0), a1 = a.GetLength(1);
            for (int i = 0; i < a0; ++i) {
                for (int j = 0; j < a1 - 1; ++j) Out(a[i, j] + " ");
                OutLine(a[i, a1 - 1]);
            }
        }
        public void ol<T>(params T[] a) => OutLine(string.Join(" ", a));
        public void YN(bool f) => OutLine(f ? "YES" : "NO");
        public void Yn(bool f) => OutLine(f ? "Yes" : "No");
        public void yn(bool f) => OutLine(f ? "yes" : "no");
        #endregion
    }
    class Mat
    {
        public long mod = 1000000007; //10^9+7
        public long Pow(long a, long b) {
            if (b == 0) return 1;
            if (b % 2 == 1) return (a % mod * Pow(a % mod, b - 1) % mod) % mod;
            else return Pow(a * a % mod, b / 2) % mod;
        }
        public long Fact(long n) {
            long ret = 1;
            for (long i = 1; i <= n; i++) ret = (ret * i) % mod;
            return ret;
        }
        public long[,] C(int N) {
            long[,] Co = new long[N + 1, N + 1];
            (N + 1).REP(i => (i + 1).REP(j => Co[i, j] = (j == 0 || j == i) ? 1L : Co[i - 1, j - 1] + Co[i - 1, j]));
            return Co;
        }
        public long C(long n, long r) {
            if (r == 0 || n == r) return 1;
            if (n == 0) return 0;
            if (n < 0 || r < 0 || n < r) throw new ArgumentException("n or r invalid");
            else return (Fact(n) % mod * Pow((Fact(n - r) % mod * Fact(r) % mod) % mod, mod - 2) % mod) % mod;
        }
        public long NoModC(long n, long r) {
            var c = new long[r + 1];
            c[0] = 1;
            for (var i = 1; i <= n; ++i) for (var j = Math.Min(i, r); j > 0; j--) c[j] = c[j] + c[j - 1];
            return c[r];
        }
        public long H(long n, long r) => C(n + r - 1, r);
        public long P(long n, long r) => Fact(n) / Fact(n - r);
        public long Lcm(long a, long b) => a * (b / Gcd(a, b));
        public long Lcm(params long[] a) => a.Aggregate((v, n) => Lcm(v, n));
        public long Gcd(long a, long b) {
            if (a < b) Swap(ref a, ref b);
            return b == 0 ? a : Gcd(b, a % b);
        }
        public long Gcd(params long[] array) => array.Aggregate((v, n) => Gcd(v, n));
        public T Max<T>(params T[] a) => a.Max();
        public T Min<T>(params T[] a) => a.Min();
        public void Swap<T>(ref T a, ref T b) {
            T tmp = a;
            a = b;
            b = tmp;
        }
        public double Dis(int x1, int y1, int x2, int y2) => Math.Sqrt(Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2));
        public int ManhattanDis(int x1, int y1, int x2, int y2) => Math.Abs(x1 - x2) + Math.Abs(y1 - y2);
        public long Tousa(long a, long d, long n) { return a + (n - 1) * d; }
        public long TousaSum(long a, long d, long n) { return n * (2 * a + (n - 1) * d) / 2; }
        public Dictionary<long, long> PrimeFactor(long n) {
            var ret = new Dictionary<long, long>();
            for (int i = 2; i * i <= n; ++i) {
                if (!ret.ContainsKey(i)) ret[i] = 0;
                while (n % i == 0) {
                    ++ret[i];
                    n /= i;
                }
            }
            return ret.Where(kp => kp.Value != 0).ToDictionary(kp => kp.Key, kp => kp.Value);
        }
    }
    public struct Edge : IComparable<Edge>
    {
        public int To;
        public long Cost;
        public Edge(int to, long cost) {
            To = to;
            Cost = cost;
        }
        public int CompareTo(Edge e) => Cost.CompareTo(e.Cost);
    }
    #endregion
    #region MyEx
    static class StringEx
    {
        public static string Reversed(this string s) => string.Join("", s.Reverse());
        public static string Repeated(this string s, int n) => string.Concat(Enumerable.Repeat(s, n).ToArray());
        public static string toString(this char[] a) => new string(a);
        public static int toInt(this string s) {
            int n;
            return (int.TryParse(s.TrimStart('0'), out n)) ? n : 0;
        }
        public static int toInt(this char c) => toInt(c.ToString());
        public static int toInt(this char[] c) => toInt(c.toString());
        public static long toLong(this string s) {
            long n;
            return (long.TryParse(s.TrimStart('0'), out n)) ? n : 0L;
        }
        public static long toLong(this char c) => toLong(c.ToString());
        public static long toLong(this char[] c) => toLong(c.toString());
    }
    static class NumericEx
    {
        public static string toString(this double d) => d.ToString("R", CultureInfo.InvariantCulture);
        public static string Pad0<T>(this T s, int n) => s.ToString().PadLeft(n, '0');
        public static string RoundOff(this double v, int n)
            => Math.Round(v, n - 1, MidpointRounding.AwayFromZero).toString();
        public static string RoundUp(this double v) => Math.Ceiling(v).toString();
        public static string RoundDown(this double v) => Math.Floor(v).toString();
        public static bool Odd(this int v) => (v & 1) != 0;
        public static bool Odd(this long v) => (v & 1) != 0;
        public static void REP(this int v, Action<int> act) {
            for (int i = 0; i < v; ++i) act(i);
        }
        public static void REPR(this int v, Action<int> act) {
            for (int i = v - 1; i >= 0; --i) act(i);
        }
        public static void EREP(this int v, Action<int> act) => (v + 1).REP(act);
    }
    static class ArrayEx
    {
        public static T[] Sort<T>(this T[] a) {
            Array.Sort(a);
            return a;
        }
        public static T[] SortR<T>(this T[] a) {
            Array.Reverse(a.Sort());
            return a;
        }
        public static void Set<T>(this T[] a, T v) => a.Length.REP(i => a[i] = v);
        public static void Set<T>(this T[,] a, T v) => a.GetLength(0).REP(i => a.GetLength(1).REP(j => a[i, j] = v));
        public static void Set<T>(this T[,,] a, T v)
            => a.GetLength(0).REP(i => a.GetLength(1).REP(j => a.GetLength(2).REP(k => a[i, j, k] = v)));
        public static long BinarySearch<T>(this T[] a, long ng, long ok, Func<long, bool> check) {
            var isLowNg = Math.Min(ng, ok) == ng;
            long low = isLowNg ? ng : ok, high = isLowNg ? ok : ng;
            while (high - low > 1) {
                long mid = (high + low) >> 1;
                if (check(mid)) high = mid;
                else low = mid;
            }
            return isLowNg ? high : low;
        }
        public static long testLowerBound<T>(this T[] a, T x) where T : IComparable
            => BinarySearch(a, -1, a.Length, (mid) => a[mid].CompareTo(x) >= 0);
        public static long testUpperBound<T>(this T[] a, T x) where T : IComparable
            => BinarySearch(a, -1, a.Length, (mid) => a[mid].CompareTo(x) > 0);
        public static int LowerBound<T>(this T[] a, T x) where T : IComparable {
            int lb = -1, ub = a.Length;
            while (ub - lb > 1) {
                int mid = (ub + lb) >> 1;
                if (a[mid].CompareTo(x) >= 0) ub = mid;
                else lb = mid;
            }
            return ub;
        }
        public static int UpperBound<T>(this T[] a, T x) where T : IComparable {
            int lb = -1, ub = a.Length;
            while (ub - lb > 1) {
                int mid = (ub + lb) >> 1;
                if (a[mid].CompareTo(x) > 0) ub = mid;
                else lb = mid;
            }
            return ub;
        }
        public static int ItemsInRange<T>(this T[] a, T from, T to) where T : IComparable
            => a.UpperBound(to) - a.LowerBound(from);
    }
    public static class FunctionalEx
    {
        public static Func<T, TV> Compose<T, TU, TV>(this Func<TU, TV> f, Func<T, TU> g) { return x => f(g(x)); }
    }
    #endregion
}