using System;
using System.Collections.Generic;
using CompLib.Util;

public class Program
{
    private int N;
    private int[,] A;

    private int[] X, Y;

    private const int K = 3;

    private int[] kDx = new int[] {-2, -2, -1, -1, 1, 1, 2, 2};
    private int[] kDy = new int[] {-1, 1, -2, 2, -2, 2, -1, 1};

    private int[] rDx = new int[] {-1, 0, 0, 1};
    private int[] rDy = new int[] {0, 1, -1, 0};

    private int[] bDx = new int[] {1, 1, -1, -1};
    private int[] bDy = new int[] {-1, 1, -1, 1};

    public void Solve()
    {
        var sc = new Scanner();
        N = sc.NextInt();
        A = new int[N, N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                A[i, j] = sc.NextInt() - 1;
            }
        }

        X = new int[N * N];
        Y = new int[N * N];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                X[A[i, j]] = i;
                Y[A[i, j]] = j;
            }
        }

        var step = new int[N, N, N * N + 1, K];
        var r = new int[N, N, N * N + 1, K];
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                for (int k = 0; k <= N * N; k++)
                {
                    for (int l = 0; l < K; l++)
                    {
                        step[i, j, k, l] = int.MaxValue;
                    }
                }
            }
        }

        var q = new Queue<(int x, int y, int t, int k)>();
        for (int i = 0; i < K; i++)
        {
            step[X[0], Y[0], 1, i] = 0;
            q.Enqueue((X[0], Y[0], 1, i));
        }

        while (q.Count > 0)
        {
            var d = q.Dequeue();
            int curS = step[d.x, d.y, d.t, d.k];
            int curR = r[d.x, d.y, d.t, d.k];
            // 交換
            for (int i = 0; i < K; i++)
            {
                if (d.k == i) continue;
                ref int nextS = ref step[d.x, d.y, d.t, i];
                ref int nextR = ref r[d.x, d.y, d.t, i];
                if (curS + 1 < nextS || (curS + 1 == nextS && curR + 1 < nextR))
                {
                    nextS = curS + 1;
                    nextR = curR + 1;
                    q.Enqueue((d.x, d.y, d.t, i));
                }
            }

            // 移動
            if (d.k == 0)
            {
                // ナイト
                for (int i = 0; i < kDx.Length; i++)
                {
                    int nx = d.x + kDx[i];
                    int ny = d.y + kDy[i];
                    if (nx < 0 || nx >= N) continue;
                    if (ny < 0 || ny >= N) continue;
                    int nt = A[nx, ny] == d.t ? d.t + 1 : d.t;

                    ref int nextS = ref step[nx, ny, nt, 0];
                    ref int nextR = ref r[nx, ny, nt, 0];
                    if (curS + 1 < nextS || (curS + 1 == nextS && curR < nextR))
                    {
                        nextS = curS + 1;
                        nextR = curR;
                        q.Enqueue((nx, ny, nt, 0));
                    }
                }
            }
            else if (d.k == 1)
            {
                // ビショップ ななめ
                for (int i = 0; i < bDx.Length; i++)
                {
                    for (int j = 1;; j++)
                    {
                        int nx = d.x + bDx[i] * j;
                        int ny = d.y + bDy[i] * j;
                        if (nx < 0 || nx >= N) break;
                        if (ny < 0 || ny >= N) break;

                        int nt = A[nx, ny] == d.t ? d.t + 1 : d.t;

                        ref int nextS = ref step[nx, ny, nt, 1];
                        ref int nextR = ref r[nx, ny, nt, 1];
                        if (curS + 1 < nextS || (curS + 1 == nextS && curR < nextR))
                        {
                            nextS = curS + 1;
                            nextR = curR;
                            q.Enqueue((nx, ny, nt, 1));
                        }
                    }
                }
            }
            else if (d.k == 2)
            {
                // ルーク　たてよこ
                for (int i = 0; i < rDx.Length; i++)
                {
                    for (int j = 1;; j++)
                    {
                        int nx = d.x + rDx[i] * j;
                        int ny = d.y + rDy[i] * j;
                        if (nx < 0 || nx >= N) break;
                        if (ny < 0 || ny >= N) break;

                        int nt = A[nx, ny] == d.t ? d.t + 1 : d.t;

                        ref int nextS = ref step[nx, ny, nt, 2];
                        ref int nextR = ref r[nx, ny, nt, 2];
                        if (curS + 1 < nextS || (curS + 1 == nextS && curR < nextR))
                        {
                            nextS = curS + 1;
                            nextR = curR;
                            q.Enqueue((nx, ny, nt, 2));
                        }
                    }
                }
            }
        }

        // ゴール
        int ansS = int.MaxValue;
        int ansR = int.MaxValue;
        int lx = X[N * N - 1];
        int ly = Y[N * N - 1];
        for (int i = 0; i < 3; i++)
        {
            int ss = step[lx, ly, N * N, i];
            int rr = r[lx, ly, N * N, i];

            if (ss < ansS || (ss == ansS && rr < ansR))
            {
                ansS = ss;
                ansR = rr;
            }
        }

        Console.WriteLine($"{ansS} {ansR}");
    }

    public static void Main(string[] args) => new Program().Solve();
}

namespace CompLib.Util
{
    using System;
    using System.Linq;

    class Scanner
    {
        private string[] _line;
        private int _index;
        private const char Separator = ' ';

        public Scanner()
        {
            _line = new string[0];
            _index = 0;
        }

        public string Next()
        {
            if (_index >= _line.Length)
            {
                string s;
                do
                {
                    s = Console.ReadLine();
                } while (s.Length == 0);

                _line = s.Split(Separator);
                _index = 0;
            }

            return _line[_index++];
        }

        public string ReadLine()
        {
            _index = _line.Length;
            return Console.ReadLine();
        }

        public int NextInt() => int.Parse(Next());
        public long NextLong() => long.Parse(Next());
        public double NextDouble() => double.Parse(Next());
        public decimal NextDecimal() => decimal.Parse(Next());
        public char NextChar() => Next()[0];
        public char[] NextCharArray() => Next().ToCharArray();

        public string[] Array()
        {
            string s = Console.ReadLine();
            _line = s.Length == 0 ? new string[0] : s.Split(Separator);
            _index = _line.Length;
            return _line;
        }

        public int[] IntArray() => Array().Select(int.Parse).ToArray();
        public long[] LongArray() => Array().Select(long.Parse).ToArray();
        public double[] DoubleArray() => Array().Select(double.Parse).ToArray();
        public decimal[] DecimalArray() => Array().Select(decimal.Parse).ToArray();
    }
}


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tidbits;

class testcodeforces
{
    int N;
    int[,] board;
    Dictionary<int, Tuple<int, int>> locations;

    public static void Main()
    {
        testcodeforces obj = new testcodeforces();
        obj.ThreePieces();
    }

    enum Pawn
    {
        Bishop = 0,
        Knight,
        Rook
    }
    class Move : IComparable<Move>
    {
        public int Moves { get; set; }
        public int Rep { get; set; }

        public int Num { get; set; }
        public Pawn pawn { get; set; }
        public int CompareTo(Move other)
        {
            if (Moves < other.Moves) return -1;
            if (Moves > other.Moves) return 1;

            if (Moves == other.Moves) return Rep.CompareTo(other.Rep);

            return 0;
        }
    }
    private void ThreePieces()
    {
        N = int.Parse(Console.ReadLine());

        board = new int[N, N];
        locations = new Dictionary<int, Tuple<int, int>>();

        for (int i = 0; i < N; i++)
        {
            var array = Array.ConvertAll(Console.ReadLine().Split(new char[] { ' ' }), int.Parse);

            for (int j = 0; j < N; j++)
            {
                board[i, j] = array[j];
                locations.Add(array[j], Tuple.Create(i + 1, j + 1));
            }
        }

        //Min of all
        #region rook Distances
        //Find rook distances
        var rook_distances = new Tuple<int, int>[(N * N) + 1];
        rook_distances[1] = Tuple.Create(0, 0);

        for (int i = 2; i <= N * N; i++)
        {
            var current_location = locations[i - 1];
            var new_location = locations[i];

            if (current_location.Item1 == new_location.Item1 ||
                current_location.Item2 == new_location.Item2)
                rook_distances[i] = Tuple.Create(1, 0);
            else
                rook_distances[i] = Tuple.Create(2, 0);
        }
        #endregion

        #region Bishop Distances
        //Find Bishop Distances
        var bishop_distances = new Tuple<int, int>[(N * N) + 1];
        bishop_distances[1] = Tuple.Create(0, 0);

        for (int i = 2; i <= N * N; i++)
        {
            var current_location = locations[i - 1];
            var new_location = locations[i];

            if ((current_location.Item1 + current_location.Item2) % 2 != (new_location.Item1 + new_location.Item2) % 2)
                bishop_distances[i] = Tuple.Create(int.MaxValue, 0);
            else
            {
                bool found = false;
                //Move North East
                for (int k = 1; k <= Math.Min(current_location.Item1 - 1, N - current_location.Item2); k++)
                {
                    if (new_location.Item1 == current_location.Item1 - k && new_location.Item2 == current_location.Item2 + k)
                    {
                        bishop_distances[i] = Tuple.Create(1, 0);
                        found = true;
                        break;
                    }
                }

                //Move South west
                if (!found)
                {
                    for (int k = 1; k <= Math.Min(N - current_location.Item1, current_location.Item2 - 1); k++)
                    {
                        if (new_location.Item1 == current_location.Item1 + k && new_location.Item2 == current_location.Item2 - k)
                        {
                            bishop_distances[i] = Tuple.Create(1, 0);
                            found = true;
                            break;
                        }
                    }
                }

                //Move South east
                if (!found)
                {
                    for (int k = 1; k <= Math.Min(N - current_location.Item1, N - current_location.Item2 - 1); k++)
                    {
                        if (new_location.Item1 == current_location.Item1 + k && new_location.Item2 == current_location.Item2 + k)
                        {
                            bishop_distances[i] = Tuple.Create(1, 0);
                            found = true;
                            break;
                        }
                    }
                }

                //Move North West
                if (!found)
                {
                    for (int k = 1; k <= Math.Min(current_location.Item1 - 1, current_location.Item2 - 1); k++)
                    {
                        if (new_location.Item1 == current_location.Item1 - k && new_location.Item2 == current_location.Item2 - k)
                        {
                            bishop_distances[i] = Tuple.Create(1, 0);
                            found = true;
                            break;
                        }
                    }
                }

                if (!found)
                {
                    bishop_distances[i] = Tuple.Create(2, 0);
                }
            }
        }
        #endregion

        #region Knight Distances
        //Find Knight Distances
        var X = new int[] { 2, 2, -2, -2, 1, 1, -1, -1 };
        var Y = new int[] { -1, 1, -1, 1, 2, -2, 2, -2 };

        var Knight_distances = new Tuple<int, int>[(N * N) + 1];
        Knight_distances[1] = Tuple.Create(0, 0);

        for (int i = 2; i <= N * N; i++)
        {
            var current_location = locations[i - 1];
            var new_location = locations[i];

            var list = new List<Tuple<int, int>>();

            bool found = false;

            for (int t = 0; t < 8; t++)
            {
                var new_X = current_location.Item1 + X[t];
                var new_Y = current_location.Item2 + Y[t];
                if (new_X == new_location.Item1 && new_Y == new_location.Item2)
                {
                    Knight_distances[i] = Tuple.Create(1, 0);
                    found = true;
                    break;
                }
                else
                {
                    if (new_X >= 1 && new_X <= N && new_Y >= 1 && new_Y <= N)
                        list.Add(Tuple.Create(new_X, new_Y));
                }
            }

            if (!found)
            {
                for (int l = 0; l < list.Count; l++)
                {
                    for (int t = 0; t < 8; t++)
                    {
                        var new_X = list[l].Item1 + X[t];
                        var new_Y = list[l].Item2 + Y[t];
                        if (new_X == new_location.Item1 && new_Y == new_location.Item2)
                        {
                            Knight_distances[i] = Tuple.Create(2, 0);
                            found = true;
                            break;
                        }
                    }
                }
            }

            if (!found) Knight_distances[i] = Tuple.Create(int.MaxValue, 0);

        }
        #endregion

        var minheap = new MinHeap<Move>();

        var states = new Move[3][];
        states[0] = new Move[(N * N) + 1];
        states[1] = new Move[(N * N) + 1];
        states[2] = new Move[(N * N) + 1];

        for (int j = 1; j <= N * N; j++)
            states[0][j] = new Move() { pawn = Pawn.Bishop, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };
        for (int j = 1; j <= N * N; j++)
            states[1][j] = new Move() { pawn = Pawn.Knight, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };
        for (int j = 1; j <= N * N; j++)
            states[2][j] = new Move() { pawn = Pawn.Rook, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };

        states[0][1] = new Move() { pawn = Pawn.Bishop, Num = 1, Moves = 0, Rep = 0 };
        states[1][1] = new Move() { pawn = Pawn.Knight, Num = 1, Moves = 0, Rep = 0 };
        states[2][1] = new Move() { pawn = Pawn.Rook, Num = 1, Moves = 0, Rep = 0 };

        minheap.Add(states[0][1]);
        minheap.Add(states[1][1]);
        minheap.Add(states[2][1]);

        while (minheap.Count > 0)
        {
            var item = minheap.ExtractMin();

            Pawn p = item.pawn;
            int currentnum = item.Num;
            int intPaws = (int)p;

            Console.WriteLine("*******************");
            Console.WriteLine("" + p + " currentnum " + currentnum);

            if (currentnum == N * N) break;

            if (p == Pawn.Bishop)
            {
                //Get Bishop distance
                var dist = bishop_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 < states[0][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 == states[0][currentnum + 1].Moves && item.Rep < states[0][currentnum + 1].Rep))
                    {
                        states[0][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1,
                            pawn = Pawn.Bishop,
                            Rep = item.Rep
                        };

                        minheap.Add(states[0][currentnum + 1]);
                    }
                }

                //Get Knight distance
                dist = Knight_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[1][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[1][currentnum + 1].Moves && item.Rep + 1 < states[1][currentnum + 1].Rep))
                    {
                        states[1][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Knight,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[1][currentnum + 1]);
                    }
                }

                //Get Rook distance
                dist = rook_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Rook,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }
            }
            else if (p == Pawn.Knight)
            {
                var dist = Knight_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 < states[1][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 == states[1][currentnum + 1].Moves && item.Rep < states[1][currentnum + 1].Rep))
                    {
                        states[1][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1,
                            pawn = Pawn.Knight,
                            Rep = item.Rep
                        };

                        minheap.Add(states[1][currentnum + 1]);
                    }
                }

                dist = rook_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Rook,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }

                dist = bishop_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[0][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[0][currentnum + 1].Moves && item.Rep + 1 < states[0][currentnum + 1].Rep))
                    {
                        states[0][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Bishop,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[0][currentnum + 1]);
                    }
                }
            }
            else if (p == Pawn.Rook)
            {
                var dist = rook_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 == states[2][currentnum + 1].Moves && item.Rep < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1,
                            pawn = Pawn.Rook,
                            Rep = item.Rep
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }

                dist = bishop_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[0][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[0][currentnum + 1].Moves && item.Rep + 1 < states[0][currentnum + 1].Rep))
                    {
                        states[0][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Bishop,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[0][currentnum + 1]);
                    }
                }

                dist = Knight_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Knight,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }
            }
        }

        int res = int.MaxValue;

        res = Math.Min(states[1][N * N].Moves, res);
        res = Math.Min(states[2][N * N].Moves, res);
        res = Math.Min(states[0][N * N].Moves, res);

        int moves = int.MaxValue;

        if (res == states[0][N * N].Moves)
            moves = Math.Min(states[0][N * N].Rep, moves);

        if (res == states[1][N * N].Moves)
            moves = Math.Min(states[1][N * N].Rep, moves);
        if (res == states[2][N * N].Moves)
            moves = Math.Min(states[2][N * N].Rep, moves);

        Console.WriteLine("" + res + " " + moves);
    }
}


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tidbits;

 class MinHeap<T> where T : IComparable<T>
    {
        public IList<T> m_array;

        public MinHeap()
        {
            m_array = new List<T>();
        }
        public T GetRoot()
        {
            return m_array[0];
        }

        public T ExtractMin()
        {
            var result = m_array[0];
            m_array[0] = m_array[Count - 1];
            m_array.RemoveAt(m_array.Count - 1);
            ShiftDown(0);

            return result;
        }

        public void Remove(int index)
        {
        }
        public void ShiftDown(int index)
        {
            int left = 2 * index + 1;
            int right = 2 * index + 2;
            int Index = index;

            if (left < Count && m_array[index].CompareTo(m_array[left]) > 0)
            {
                index = left;
            }

            if (right < Count && m_array[index].CompareTo(m_array[right]) > 0)
            {
                index = right;
            }

            if (index != Index)
            {
                var temp = m_array[Index];
                m_array[Index] = m_array[index];
                m_array[index] = temp;

                ShiftDown(index);
            }
        }

        public int Count
        {
            get
            {
                return m_array.Count();
            }
        }

        private void Balance(int index)
        {
            if (index < 0)
            {
                return;
            }

            int parent = (index - 1) / 2;

            if (m_array[parent].CompareTo(m_array[index]) > 0)
            {
                var temp = m_array[parent];
                m_array[parent] = m_array[index];
                m_array[index] = temp;
                Balance(parent);
            }
        }

        public void Add(T number)
        {
            m_array.Add(number);
            BuildHeap();
            //Balance(m_array.Count - 1);
        }

        private void BuildHeap()
        {
            for (int i = Count / 2; i >= 0; i--)
            {
                Heapify(m_array, i);
            }
        }

        private void Heapify(IList<T> array, int index)
        {
            int N = array.Count;

            int Index = index;
            int left = 2 * index + 1;
            int right = 2 * index + 2;

            if (left < N && array[left].CompareTo(array[index]) < 0)
            {
                index = left;
            }

            if (right < N && array[right].CompareTo(array[index]) < 0)
            {
                index = right;
            }

            if (index != Index)
            {
                var temp = array[Index];
                array[Index] = array[index];
                array[index] = temp;

                Heapify(array, index);
            }

        }
    }

class testcodeforces
{
    int N;
    int[,] board;
    Dictionary<int, Tuple<int, int>> locations;

    public static void Main()
    {
        testcodeforces obj = new testcodeforces();
        obj.ThreePieces();
    }

    enum Pawn
    {
        Bishop = 0,
        Knight,
        Rook
    }
    class Move : IComparable<Move>
    {
        public int Moves { get; set; }
        public int Rep { get; set; }

        public int Num { get; set; }
        public Pawn pawn { get; set; }
        public int CompareTo(Move other)
        {
            if (Moves < other.Moves) return -1;
            if (Moves > other.Moves) return 1;

            if (Moves == other.Moves) return Rep.CompareTo(other.Rep);

            return 0;
        }
    }
    private void ThreePieces()
    {
        N = int.Parse(Console.ReadLine());

        board = new int[N, N];
        locations = new Dictionary<int, Tuple<int, int>>();

        for (int i = 0; i < N; i++)
        {
            var array = Array.ConvertAll(Console.ReadLine().Split(new char[] { ' ' }), int.Parse);

            for (int j = 0; j < N; j++)
            {
                board[i, j] = array[j];
                locations.Add(array[j], Tuple.Create(i + 1, j + 1));
            }
        }

        //Min of all
        #region rook Distances
        //Find rook distances
        var rook_distances = new Tuple<int, int>[(N * N) + 1];
        rook_distances[1] = Tuple.Create(0, 0);

        for (int i = 2; i <= N * N; i++)
        {
            var current_location = locations[i - 1];
            var new_location = locations[i];

            if (current_location.Item1 == new_location.Item1 ||
                current_location.Item2 == new_location.Item2)
                rook_distances[i] = Tuple.Create(1, 0);
            else
                rook_distances[i] = Tuple.Create(2, 0);
        }
        #endregion

        #region Bishop Distances
        //Find Bishop Distances
        var bishop_distances = new Tuple<int, int>[(N * N) + 1];
        bishop_distances[1] = Tuple.Create(0, 0);

        for (int i = 2; i <= N * N; i++)
        {
            var current_location = locations[i - 1];
            var new_location = locations[i];

            if ((current_location.Item1 + current_location.Item2) % 2 != (new_location.Item1 + new_location.Item2) % 2)
                bishop_distances[i] = Tuple.Create(int.MaxValue, 0);
            else
            {
                bool found = false;
                //Move North East
                for (int k = 1; k <= Math.Min(current_location.Item1 - 1, N - current_location.Item2); k++)
                {
                    if (new_location.Item1 == current_location.Item1 - k && new_location.Item2 == current_location.Item2 + k)
                    {
                        bishop_distances[i] = Tuple.Create(1, 0);
                        found = true;
                        break;
                    }
                }

                //Move South west
                if (!found)
                {
                    for (int k = 1; k <= Math.Min(N - current_location.Item1, current_location.Item2 - 1); k++)
                    {
                        if (new_location.Item1 == current_location.Item1 + k && new_location.Item2 == current_location.Item2 - k)
                        {
                            bishop_distances[i] = Tuple.Create(1, 0);
                            found = true;
                            break;
                        }
                    }
                }

                //Move South east
                if (!found)
                {
                    for (int k = 1; k <= Math.Min(N - current_location.Item1, N - current_location.Item2 - 1); k++)
                    {
                        if (new_location.Item1 == current_location.Item1 + k && new_location.Item2 == current_location.Item2 + k)
                        {
                            bishop_distances[i] = Tuple.Create(1, 0);
                            found = true;
                            break;
                        }
                    }
                }

                //Move North West
                if (!found)
                {
                    for (int k = 1; k <= Math.Min(current_location.Item1 - 1, current_location.Item2 - 1); k++)
                    {
                        if (new_location.Item1 == current_location.Item1 - k && new_location.Item2 == current_location.Item2 - k)
                        {
                            bishop_distances[i] = Tuple.Create(1, 0);
                            found = true;
                            break;
                        }
                    }
                }

                if (!found)
                {
                    bishop_distances[i] = Tuple.Create(2, 0);
                }
            }
        }
        #endregion

        #region Knight Distances
        //Find Knight Distances
        var X = new int[] { 2, 2, -2, -2, 1, 1, -1, -1 };
        var Y = new int[] { -1, 1, -1, 1, 2, -2, 2, -2 };

        var Knight_distances = new Tuple<int, int>[(N * N) + 1];
        Knight_distances[1] = Tuple.Create(0, 0);

        for (int i = 2; i <= N * N; i++)
        {
            var current_location = locations[i - 1];
            var new_location = locations[i];

            var list = new List<Tuple<int, int>>();

            bool found = false;

            for (int t = 0; t < 8; t++)
            {
                var new_X = current_location.Item1 + X[t];
                var new_Y = current_location.Item2 + Y[t];
                if (new_X == new_location.Item1 && new_Y == new_location.Item2)
                {
                    Knight_distances[i] = Tuple.Create(1, 0);
                    found = true;
                    break;
                }
                else
                {
                    if (new_X >= 1 && new_X <= N && new_Y >= 1 && new_Y <= N)
                        list.Add(Tuple.Create(new_X, new_Y));
                }
            }

            if (!found)
            {
                for (int l = 0; l < list.Count; l++)
                {
                    for (int t = 0; t < 8; t++)
                    {
                        var new_X = list[l].Item1 + X[t];
                        var new_Y = list[l].Item2 + Y[t];
                        if (new_X == new_location.Item1 && new_Y == new_location.Item2)
                        {
                            Knight_distances[i] = Tuple.Create(2, 0);
                            found = true;
                            break;
                        }
                    }
                }
            }

            if (!found) Knight_distances[i] = Tuple.Create(int.MaxValue, 0);

        }
        #endregion

        var minheap = new MinHeap<Move>();

        var states = new Move[3][];
        states[0] = new Move[(N * N) + 1];
        states[1] = new Move[(N * N) + 1];
        states[2] = new Move[(N * N) + 1];

        for (int j = 1; j <= N * N; j++)
            states[0][j] = new Move() { pawn = Pawn.Bishop, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };
        for (int j = 1; j <= N * N; j++)
            states[1][j] = new Move() { pawn = Pawn.Knight, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };
        for (int j = 1; j <= N * N; j++)
            states[2][j] = new Move() { pawn = Pawn.Rook, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };

        states[0][1] = new Move() { pawn = Pawn.Bishop, Num = 1, Moves = 0, Rep = 0 };
        states[1][1] = new Move() { pawn = Pawn.Knight, Num = 1, Moves = 0, Rep = 0 };
        states[2][1] = new Move() { pawn = Pawn.Rook, Num = 1, Moves = 0, Rep = 0 };

        minheap.Add(states[0][1]);
        minheap.Add(states[1][1]);
        minheap.Add(states[2][1]);

        while (minheap.Count > 0)
        {
            var item = minheap.ExtractMin();

            Pawn p = item.pawn;
            int currentnum = item.Num;
            int intPaws = (int)p;

           // Console.WriteLine("*******************");
           // Console.WriteLine("" + p + " currentnum " + currentnum);

            if (currentnum == N * N) break;

            if (p == Pawn.Bishop)
            {
                //Get Bishop distance
                var dist = bishop_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 < states[0][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 == states[0][currentnum + 1].Moves && item.Rep < states[0][currentnum + 1].Rep))
                    {
                        states[0][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1,
                            pawn = Pawn.Bishop,
                            Rep = item.Rep
                        };

                        minheap.Add(states[0][currentnum + 1]);
                    }
                }

                //Get Knight distance
                dist = Knight_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[1][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[1][currentnum + 1].Moves && item.Rep + 1 < states[1][currentnum + 1].Rep))
                    {
                        states[1][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Knight,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[1][currentnum + 1]);
                    }
                }

                //Get Rook distance
                dist = rook_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Rook,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }
            }
            else if (p == Pawn.Knight)
            {
                var dist = Knight_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 < states[1][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 == states[1][currentnum + 1].Moves && item.Rep < states[1][currentnum + 1].Rep))
                    {
                        states[1][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1,
                            pawn = Pawn.Knight,
                            Rep = item.Rep
                        };

                        minheap.Add(states[1][currentnum + 1]);
                    }
                }

                dist = rook_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Rook,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }

                dist = bishop_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[0][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[0][currentnum + 1].Moves && item.Rep + 1 < states[0][currentnum + 1].Rep))
                    {
                        states[0][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Bishop,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[0][currentnum + 1]);
                    }
                }
            }
            else if (p == Pawn.Rook)
            {
                var dist = rook_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 == states[2][currentnum + 1].Moves && item.Rep < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1,
                            pawn = Pawn.Rook,
                            Rep = item.Rep
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }

                dist = bishop_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[0][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[0][currentnum + 1].Moves && item.Rep + 1 < states[0][currentnum + 1].Rep))
                    {
                        states[0][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Bishop,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[0][currentnum + 1]);
                    }
                }

                dist = Knight_distances[currentnum + 1];
                if (dist.Item1 != int.MaxValue)
                {
                    if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                        || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                    {
                        states[2][currentnum + 1] = new Move()
                        {
                            Num = currentnum + 1,
                            Moves = item.Moves + dist.Item1 + 1,
                            pawn = Pawn.Knight,
                            Rep = item.Rep + 1
                        };

                        minheap.Add(states[2][currentnum + 1]);
                    }
                }
            }
        }

        int res = int.MaxValue;

        res = Math.Min(states[1][N * N].Moves, res);
        res = Math.Min(states[2][N * N].Moves, res);
        res = Math.Min(states[0][N * N].Moves, res);

        int moves = int.MaxValue;

        if (res == states[0][N * N].Moves)
            moves = Math.Min(states[0][N * N].Rep, moves);

        if (res == states[1][N * N].Moves)
            moves = Math.Min(states[1][N * N].Rep, moves);
        if (res == states[2][N * N].Moves)
            moves = Math.Min(states[2][N * N].Rep, moves);

        Console.WriteLine("" + res + " " + moves);
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleTidbits
{
      class MinHeap<T> where T : IComparable
    {
        public IList<T> m_array;

        public MinHeap()
        {
            m_array = new List<T>();
        }
        public T GetRoot()
        {
            return m_array[0];
        }

        public T ExtractMin()
        {
            var result = m_array[0];
            m_array[0] = m_array[Count - 1];
            m_array.RemoveAt(m_array.Count - 1);
            ShiftDown(0);

            return result;
        }

        public void Remove(int index)
        {
        }

        public void ShiftDown(int index)
        {
            int left = 2 * index + 1;
            int right = 2 * index + 2;
            int Index = index;

            if (left < Count && m_array[index].CompareTo(m_array[left]) > 0)
            {
                index = left;
            }

            if (right < Count && m_array[index].CompareTo(m_array[right]) > 0)
            {
                index = right;
            }

            if (index != Index)
            {
                var temp = m_array[Index];
                m_array[Index] = m_array[index];
                m_array[index] = temp;

                ShiftDown(index);
            }
        }

        public int Count
        {
            get
            {
                return m_array.Count();
            }
        }

        private void Balance(int index)
        {
            if (index < 0)
            {
                return;
            }

            int parent = (index - 1) / 2;

            if (m_array[parent].CompareTo(m_array[index]) > 0)
            {
                var temp = m_array[parent];
                m_array[parent] = m_array[index];
                m_array[index] = temp;
                Balance(parent);
            }
        }

        public void Add(T number)
        {
            m_array.Add(number);
            //BuildHeap();
            Balance(m_array.Count - 1);
        }

        private void BuildHeap()
        {
            for (int i = Count / 2; i >= 0; i--)
            {
                Heapify(m_array, i);
            }
        }
        private void Heapify(IList<T> array, int index)
        {
            int N = array.Count;

            int Index = index;
            int left = 2 * index + 1;
            int right = 2 * index + 2;

            if (left < N && array[left].CompareTo(array[index]) < 0)
            {
                index = left;
            }

            if (right < N && array[right].CompareTo(array[index]) < 0)
            {
                index = right;
            }

            if (index != Index)
            {
                var temp = array[Index];
                array[Index] = array[index];
                array[index] = temp;

                Heapify(array, index);
            }

        }
    }

    class JustCodeForces
    {
        int N;
        int[,] board;
        Dictionary<int, Tuple<int, int>> locations;

        public static void Main()
        {
            JustCodeForces obj = new JustCodeForces();

            while (true)
                obj.ThreePieces();
        }

        enum Pawn
        {
            Bishop = 0,
            Knight,
            Rook
        }
        class Move : IComparable
        {
            public int Moves { get; set; }
            public int Rep { get; set; }

            public int Num { get; set; }
            public Pawn pawn { get; set; }
            public int CompareTo(object o)
            {
                var other = o as Move;
                if (Moves < other.Moves) return -1;
                if (Moves > other.Moves) return 1;

                if (Moves == other.Moves) return Rep.CompareTo(other.Rep);

                return -1;
            }
        }
        private void ThreePieces()
        {
            N = int.Parse(Console.ReadLine());

            board = new int[N, N];
            locations = new Dictionary<int, Tuple<int, int>>();

            for (int i = 0; i < N; i++)
            {
                var array = Array.ConvertAll(Console.ReadLine().Split(new char[] { ' ' }), int.Parse);

                for (int j = 0; j < N; j++)
                {
                    board[i, j] = array[j];
                    locations.Add(array[j], Tuple.Create(i + 1, j + 1));
                }
            }

            //Min of all
            #region rook Distances
            //Find rook distances
            var rook_distances = new Tuple<int, int>[(N * N) + 1];
            rook_distances[1] = Tuple.Create(0, 0);

            for (int i = 2; i <= N * N; i++)
            {
                var current_location = locations[i - 1];
                var new_location = locations[i];

                if (current_location.Item1 == new_location.Item1 ||
                    current_location.Item2 == new_location.Item2)
                    rook_distances[i] = Tuple.Create(1, 0);
                else
                    rook_distances[i] = Tuple.Create(2, 0);
            }
            #endregion

            #region Bishop Distances
            //Find Bishop Distances
            var bishop_distances = new Tuple<int, int>[(N * N) + 1];
            bishop_distances[1] = Tuple.Create(0, 0);

            for (int i = 2; i <= N * N; i++)
            {
                var current_location = locations[i - 1];
                var new_location = locations[i];

                if ((current_location.Item1 + current_location.Item2) % 2 != (new_location.Item1 + new_location.Item2) % 2)
                    bishop_distances[i] = Tuple.Create(int.MaxValue, 0);
                else
                {
                    bool found = false;
                    //Move North East
                    for (int k = 1; k <= Math.Min(current_location.Item1 - 1, N - current_location.Item2); k++)
                    {
                        if (new_location.Item1 == current_location.Item1 - k && new_location.Item2 == current_location.Item2 + k)
                        {
                            bishop_distances[i] = Tuple.Create(1, 0);
                            found = true;
                            break;
                        }
                    }

                    //Move South west
                    if (!found)
                    {
                        for (int k = 1; k <= Math.Min(N - current_location.Item1, current_location.Item2 - 1); k++)
                        {
                            if (new_location.Item1 == current_location.Item1 + k && new_location.Item2 == current_location.Item2 - k)
                            {
                                bishop_distances[i] = Tuple.Create(1, 0);
                                found = true;
                                break;
                            }
                        }
                    }

                    //Move South east
                    if (!found)
                    {
                        for (int k = 1; k <= Math.Min(N - current_location.Item1, N - current_location.Item2); k++)
                        {
                            if (new_location.Item1 == current_location.Item1 + k && new_location.Item2 == current_location.Item2 + k)
                            {
                                bishop_distances[i] = Tuple.Create(1, 0);
                                found = true;
                                break;
                            }
                        }
                    }

                    //Move North West
                    if (!found)
                    {
                        for (int k = 1; k <= Math.Min(current_location.Item1 - 1, current_location.Item2 - 1); k++)
                        {
                            if (new_location.Item1 == current_location.Item1 - k && new_location.Item2 == current_location.Item2 - k)
                            {
                                bishop_distances[i] = Tuple.Create(1, 0);
                                found = true;
                                break;
                            }
                        }
                    }

                    if (!found)
                    {
                        bishop_distances[i] = Tuple.Create(2, 0);
                    }
                }
            }
            #endregion

            #region Knight Distances
            //Find Knight Distances
            var X = new int[] { 2, 2, -2, -2, 1, 1, -1, -1 };
            var Y = new int[] { -1, 1, -1, 1, 2, -2, 2, -2 };

            var Knight_distances = new Tuple<int, int>[(N * N) + 1];
            Knight_distances[1] = Tuple.Create(0, 0);

            for (int i = 2; i <= N * N; i++)
            {
                var current_location = locations[i - 1];
                var new_location = locations[i];

                var list = new List<Tuple<int, int>>();

                bool found = false;

                for (int t = 0; t < 8; t++)
                {
                    var new_X = current_location.Item1 + X[t];
                    var new_Y = current_location.Item2 + Y[t];
                    if (new_X == new_location.Item1 && new_Y == new_location.Item2)
                    {
                        Knight_distances[i] = Tuple.Create(1, 0);
                        found = true;
                        break;
                    }
                    else
                    {
                        if (new_X >= 1 && new_X <= N && new_Y >= 1 && new_Y <= N)
                            list.Add(Tuple.Create(new_X, new_Y));
                    }
                }

                var new_list = new List<Tuple<int, int>>();

                if (!found)
                {
                    for (int l = 0; l < list.Count; l++)
                    {
                        for (int t = 0; t < 8; t++)
                        {
                            var new_X = list[l].Item1 + X[t];
                            var new_Y = list[l].Item2 + Y[t];
                            if (new_X == new_location.Item1 && new_Y == new_location.Item2)
                            {
                                Knight_distances[i] = Tuple.Create(2, 0);
                                found = true;
                                break;
                            }
                            else
                            {
                                if (new_X >= 1 && new_X <= N && new_Y >= 1 && new_Y <= N)
                                    new_list.Add(Tuple.Create(new_X, new_Y));
                            }
                        }
                    }
                }

                if (!found)
                {
                    for (int l = 0; l < new_list.Count; l++)
                    {
                        for (int t = 0; t < 8; t++)
                        {
                            var new_X = new_list[l].Item1 + X[t];
                            var new_Y = new_list[l].Item2 + Y[t];
                            if (new_X == new_location.Item1 && new_Y == new_location.Item2)
                            {
                                Knight_distances[i] = Tuple.Create(3, 0);
                                found = true;
                                break;
                            }
                        }
                    }
                }

                if (!found) Knight_distances[i] = Tuple.Create(int.MaxValue, 0);

            }
            #endregion

            var minheap = new MinHeap<Move>();

            var states = new Move[3][];
            states[0] = new Move[(N * N) + 1];
            states[1] = new Move[(N * N) + 1];
            states[2] = new Move[(N * N) + 1];

            for (int j = 1; j <= N * N; j++)
                states[0][j] = new Move() { pawn = Pawn.Bishop, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };
            for (int j = 1; j <= N * N; j++)
                states[1][j] = new Move() { pawn = Pawn.Knight, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };
            for (int j = 1; j <= N * N; j++)
                states[2][j] = new Move() { pawn = Pawn.Rook, Num = j, Moves = int.MaxValue, Rep = int.MaxValue };

            states[0][1] = new Move() { pawn = Pawn.Bishop, Num = 1, Moves = 0, Rep = 0 };
            states[1][1] = new Move() { pawn = Pawn.Knight, Num = 1, Moves = 0, Rep = 0 };
            states[2][1] = new Move() { pawn = Pawn.Rook, Num = 1, Moves = 0, Rep = 0 };

            minheap.Add(states[0][1]);
            minheap.Add(states[1][1]);
            minheap.Add(states[2][1]);

            while (minheap.Count > 0)
            {
                var item = minheap.ExtractMin();

                Pawn p = item.pawn;
                int currentnum = item.Num;
                int intPaws = (int)p;

                //  Console.WriteLine("*******************");
                //  Console.WriteLine("" + p + " currentnum " + currentnum);

                if (currentnum == N * N) break;

                if (p == Pawn.Bishop)
                {
                    //Get Bishop distance
                    var dist = bishop_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 < states[0][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 == states[0][currentnum + 1].Moves && item.Rep < states[0][currentnum + 1].Rep))
                        {
                            states[0][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1,
                                pawn = Pawn.Bishop,
                                Rep = item.Rep
                            };

                            minheap.Add(states[0][currentnum + 1]);
                        }
                    }

                    //Get Knight distance
                    dist = Knight_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 + 1 < states[1][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 + 1 == states[1][currentnum + 1].Moves && item.Rep + 1 < states[1][currentnum + 1].Rep))
                        {
                            states[1][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1 + 1,
                                pawn = Pawn.Knight,
                                Rep = item.Rep + 1
                            };

                            minheap.Add(states[1][currentnum + 1]);
                        }
                    }

                    //Get Rook distance
                    dist = rook_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                        {
                            states[2][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1 + 1,
                                pawn = Pawn.Rook,
                                Rep = item.Rep + 1
                            };

                            minheap.Add(states[2][currentnum + 1]);
                        }
                    }
                }
                else if (p == Pawn.Knight)
                {
                    var dist = Knight_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 < states[1][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 == states[1][currentnum + 1].Moves && item.Rep < states[1][currentnum + 1].Rep))
                        {
                            states[1][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1,
                                pawn = Pawn.Knight,
                                Rep = item.Rep
                            };

                            minheap.Add(states[1][currentnum + 1]);
                        }
                    }

                    dist = rook_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 + 1 < states[2][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 + 1 == states[2][currentnum + 1].Moves && item.Rep + 1 < states[2][currentnum + 1].Rep))
                        {
                            states[2][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1 + 1,
                                pawn = Pawn.Rook,
                                Rep = item.Rep + 1
                            };

                            minheap.Add(states[2][currentnum + 1]);
                        }
                    }

                    dist = bishop_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 + 1 < states[0][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 + 1 == states[0][currentnum + 1].Moves && item.Rep + 1 < states[0][currentnum + 1].Rep))
                        {
                            states[0][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1 + 1,
                                pawn = Pawn.Bishop,
                                Rep = item.Rep + 1
                            };

                            minheap.Add(states[0][currentnum + 1]);
                        }
                    }
                }
                else if (p == Pawn.Rook)
                {
                    var dist = rook_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 < states[2][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 == states[2][currentnum + 1].Moves && item.Rep < states[2][currentnum + 1].Rep))
                        {
                            states[2][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1,
                                pawn = Pawn.Rook,
                                Rep = item.Rep
                            };

                            minheap.Add(states[2][currentnum + 1]);
                        }
                    }

                    dist = bishop_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 + 1 < states[0][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 + 1 == states[0][currentnum + 1].Moves && item.Rep + 1 < states[0][currentnum + 1].Rep))
                        {
                            states[0][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1 + 1,
                                pawn = Pawn.Bishop,
                                Rep = item.Rep + 1
                            };

                            minheap.Add(states[0][currentnum + 1]);
                        }
                    }

                    dist = Knight_distances[currentnum + 1];
                    if (dist.Item1 != int.MaxValue)
                    {
                        if (item.Moves + dist.Item1 + 1 < states[1][currentnum + 1].Moves
                            || (item.Moves + dist.Item1 + 1 == states[1][currentnum + 1].Moves && item.Rep + 1 < states[1][currentnum + 1].Rep))
                        {
                            states[1][currentnum + 1] = new Move()
                            {
                                Num = currentnum + 1,
                                Moves = item.Moves + dist.Item1 + 1,
                                pawn = Pawn.Knight,
                                Rep = item.Rep + 1
                            };

                            minheap.Add(states[1][currentnum + 1]);
                        }
                    }
                }
            }

            int res = int.MaxValue;

            res = Math.Min(states[1][N * N].Moves, res);
            res = Math.Min(states[2][N * N].Moves, res);
            res = Math.Min(states[0][N * N].Moves, res);

            int moves = int.MaxValue;

            if (res == states[0][N * N].Moves)
                moves = Math.Min(states[0][N * N].Rep, moves);

            if (res == states[1][N * N].Moves)
                moves = Math.Min(states[1][N * N].Rep, moves);
            if (res == states[2][N * N].Moves)
                moves = Math.Min(states[2][N * N].Rep, moves);

            Console.WriteLine("" + res + " " + moves);
        }

    }
}


using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Linq;

namespace Codeforces
{
    internal class Program
    {
        private const string Test = "E2";

        private static void Solve()
        {
            var MOD = 1000000007;
            var input = ReadIntArray();
            var n = input[0];
            var m = input[1];
            var k = input[2];
            var dp = new List<List<long>>();
            for (int i = 0; i <= 1001; i++)
            {
                dp.Add(new List<long>());
                for (int j = 0; j <= i; j++)
                {
                    if(j == 0 || j == i)
                        dp[i].Add(1);
                    else
                    {
                        dp[i].Add((dp[i-1][j-1] + dp[i - 1][j]) % MOD);
                    }
                }
            }
            var res = dp[n - 1][Math.Min(2 * k, n-1)] * dp[m - 1][Math.Min(2 * k, m-1)];
            res %= MOD;
            Console.WriteLine(res);
        }

        private static void Main()
        {
            if (Debugger.IsAttached)
            {
                Console.SetIn(new StreamReader(String.Format(@"..\..\..\..\Tests\{0}.in", Test)));
            }

            Solve();

            if (Debugger.IsAttached)
            {
                Console.In.Close();
                Console.SetIn(new StreamReader(Console.OpenStandardInput()));
                Console.ReadLine();
            }
        }

        #region Reader

        private static string Read()
        {
            return Console.ReadLine();
        }

        private static string[] ReadArray()
        {
            return Console.ReadLine().Split(' ');
        }

        private static int[] ReadIntArray()
        {
            var input = Console.ReadLine().Split(' ').Select(Int32.Parse).ToArray();
            return input;
        }

        private static int ReadInt()
        {
            return Int32.Parse(Console.ReadLine());
        }

        private static long ReadLong()
        {
            return long.Parse(Console.ReadLine());
        }

        private static int ReadNextInt(string[] input, int index)
        {
            return Int32.Parse(input[index]);
        }

        #endregion
    }
}


using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Linq;

namespace Codeforces
{
    internal class Program
    {
        private const string Test = "E2";

        private static void Solve()
        {
            var MOD = 1000000007;
            var input = ReadIntArray();
            var n = input[0];
            var m = input[1];
            var k = input[2];
            var dp = new List<List<long>>();
            for (int i = 0; i <= 1001; i++)
            {
                dp.Add(new List<long>());
                for (int j = 0; j <= i; j++)
                {
                    if(j == 0 || j == i)
                        dp[i].Add(1);
                    else
                    {
                        dp[i].Add((dp[i-1][j-1] + dp[i - 1][j]) % MOD);
                    }
                }
            }
            var res = Math.Min(n - 1, m - 1) < 2*k ? 0: dp[n - 1][2*k]*dp[m - 1][2*k];
            res %= MOD;
            Console.WriteLine(res);
        }

        private static void Main()
        {
            if (Debugger.IsAttached)
            {
                Console.SetIn(new StreamReader(String.Format(@"..\..\..\..\Tests\{0}.in", Test)));
            }

            Solve();

            if (Debugger.IsAttached)
            {
                Console.In.Close();
                Console.SetIn(new StreamReader(Console.OpenStandardInput()));
                Console.ReadLine();
            }
        }

        #region Reader

        private static string Read()
        {
            return Console.ReadLine();
        }

        private static string[] ReadArray()
        {
            return Console.ReadLine().Split(' ');
        }

        private static int[] ReadIntArray()
        {
            var input = Console.ReadLine().Split(' ').Select(Int32.Parse).ToArray();
            return input;
        }

        private static int ReadInt()
        {
            return Int32.Parse(Console.ReadLine());
        }

        private static long ReadLong()
        {
            return long.Parse(Console.ReadLine());
        }

        private static int ReadNextInt(string[] input, int index)
        {
            return Int32.Parse(input[index]);
        }

        #endregion
    }
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace SP.Solutions.CodeForces.c338_196_1
{
	public class ProgramC
	{
	    private static long bestRes = long.MaxValue;

		public static void Main()
		{
			checked
			{
			    bestRes = long.MaxValue;
			    int n = int.Parse(Console.ReadLine());
			    var arr = Console.ReadLine().Split(' ').Select(long.Parse).Distinct().ToArray();
                Array.Sort(arr);

			    var primes = GetPrimes();

			    var nodes = new List<Node>();
                for (int i = 0; i < arr.Length; i++)
                {
                    nodes.Add(new Node(arr[i], getFactors(arr[i], primes), arr[i], false, 0));
                }

			    TryBuildTrees(nodes);
                Console.WriteLine(bestRes);
			}
		}

	    private static void TryBuildTrees(List<Node> nodes)
	    {
	        for (int i = 0 ; i  <nodes.Count ; i++)
	        for (int j = 0 ; j  <nodes.Count ; j++) if (j != i && !nodes[j].HasParent && nodes[i].Rem%nodes[j].N == 0)
	        {
	            var newNodes = new List<Node>();
                for (int k = 0; k < nodes.Count; k++) if (k != i && k != j) newNodes.Add(nodes[k]);
	            int add = nodes[j].Factors > 1 ? 1 : 0;
	            newNodes.Add(new Node(nodes[i].N, nodes[i].Factors, nodes[i].Rem/nodes[j].N, false, nodes[i].addFactors + nodes[j].addFactors + add));
                newNodes.Add(new Node(nodes[j].N, nodes[j].Factors, nodes[j].Rem, true, nodes[j].addFactors));
                TryBuildTrees(newNodes);
	        }

	        CalcPrice(nodes);
	    }

	    private static void CalcPrice(List<Node> nodes)
	    {
	        int n = 0;
	        long res = 0;
            foreach (var node in nodes) if (!node.HasParent)
            {
                if (node.Factors > 1) res++;
                res += node.Factors + node.addFactors;
                n++;
            }
	        if (n > 1) res++;
	        bestRes = Math.Min(bestRes, res);
	    }

	    static int getFactors(long n, long[] primes)
        {
            int res = 0;
            int i = 0;
            while (n > 1)
            {
                if (n%primes[i] == 0)
                {
                    res++;
                    n /= primes[i];
                }
                else i++;
            }
            return res;
        }

        class Node
        {
            public override string ToString()
            {
                return string.Format("HasParent: {0}, N: {1}, Factors: {2}, Rem: {3}", HasParent, N, Factors, Rem);
            }

            public bool HasParent;
            public readonly long N;
            public readonly int Factors;
            public readonly long Rem;
            public readonly int addFactors;

            public Node(long n, int factors, long rem, bool hasParent, int addFactors)
            {
                HasParent = hasParent;
                this.addFactors = addFactors;
                N = n;
                Factors = factors;
                Rem = rem;
            }
        }

	    private static long[] GetPrimes()
	    {
	        const int max = 1000000;
	        var primes = new List<long>(80000);
	        primes.Add(2);
	        var isNotPrime = new bool[max + 1];
            for (int i = 3 ; i<= max ; i+=2) if (!isNotPrime[i])
            {
                primes.Add(i);
                for (int j = i*i; j <= max && j > 0; j += i) isNotPrime[j] = true;
            }
	        return primes.ToArray();
	    }
	}
}


using System;
using System.Collections.Generic;
using System.Linq;

namespace SP.Solutions.CodeForces.c338_196_1
{
	public class ProgramC
	{
	    private static long bestRes = long.MaxValue;

		public static void Main()
		{
			checked
			{
			    bestRes = long.MaxValue;
			    int n = int.Parse(Console.ReadLine());
			    var arr = Console.ReadLine().Split(' ').Select(long.Parse).Distinct().ToArray();
                Array.Sort(arr);

			    var primes = GetPrimes();

			    var nodes = new List<Node>();
                for (int i = 0; i < arr.Length; i++)
                {
                    nodes.Add(new Node(arr[i], getFactors(arr[i], primes), arr[i], false, 0));
                }

			    TryBuildTrees(nodes, 0);
                Console.WriteLine(bestRes);
			}
		}

	    private static void TryBuildTrees(List<Node> nodes, int minJ)
	    {
	        var noWay = true;
            for (int j = minJ; j < nodes.Count; j++)
                for (int i = j + 1; i < nodes.Count; i++)
                if (j != i && !nodes[j].HasParent && nodes[i].Rem%nodes[j].N == 0 && !nodes[i].HasParent)
	        {
	            noWay = false;
	            int add = nodes[j].Factors > 1 ? 1 : 0;

	            var r1 = nodes[i].Rem;
	            var add1 = nodes[i].addFactors;

	            nodes[i].Rem = nodes[i].Rem/nodes[j].N;
	            nodes[i].addFactors = nodes[i].addFactors + nodes[j].addFactors + add;
	            nodes[j].HasParent = true;

                TryBuildTrees(nodes, minJ);

                nodes[j].HasParent = false;
                nodes[i].Rem = r1;
                nodes[i].addFactors = add1;
            }
            if (noWay)
	            CalcPrice(nodes);
	    }

	    private static void CalcPrice(List<Node> nodes)
	    {
	        int n = 0;
	        long res = 0;
            foreach (var node in nodes) if (!node.HasParent)
            {
                if (node.Factors > 1) res++;
                res += node.Factors + node.addFactors;
                n++;
            }
	        if (n > 1) res++;
	        bestRes = Math.Min(bestRes, res);
	    }

	    static int getFactors(long n, long[] primes)
        {
            int res = 0;
            int i = 0;
            while (n > 1 && i < primes.Length)
            {
                if (n%primes[i] == 0)
                {
                    res++;
                    n /= primes[i];
                }
                else i++;
            }
	        if (i == primes.Length) res++;
            return res;
        }

        class Node
        {
            public override string ToString()
            {
                return string.Format("HasParent: {0}, N: {1}, Factors: {2}, Rem: {3}", HasParent, N, Factors, Rem);
            }

            public bool HasParent;
            public readonly long N;
            public int Factors;
            public long Rem;
            public int addFactors;

            public Node(long n, int factors, long rem, bool hasParent, int addFactors)
            {
                HasParent = hasParent;
                this.addFactors = addFactors;
                N = n;
                Factors = factors;
                Rem = rem;
            }
        }

	    private static long[] GetPrimes()
	    {
	        const int max = 1000000;
	        var primes = new List<long>(80000);
	        primes.Add(2);
	        var isNotPrime = new bool[max + 1];
            for (int i = 3 ; i<= max ; i+=2) if (!isNotPrime[i])
            {
                primes.Add(i);
                for (int j = i*i; j <= max && j > 0; j += i) isNotPrime[j] = true;
            }
	        return primes.ToArray();
	    }
	}
}


// See https://aka.ms/new-console-template for more information

(int x, int y) = ReadTwoInts();
Console.WriteLine(x * (y - 1));

#region Read
static int ReadInt() => int.Parse(Console.ReadLine());
static (int x, int y) ReadTwoInts()
{
	var ints = ReadInts();
	return (ints[0], ints[1]);
}
static string ReadString() => Console.ReadLine();
static List<string> ReadStrings() => Console.ReadLine().Split(' ').ToList();
static List<int> ReadInts()
{
	List<string> strings = ReadStrings();
	List<int> ints = new();
	for (int i = 0; i < strings.Count; i++)
	{
		ints.Add(int.Parse(strings[i]));
	}
	return ints;
}
#endregion


// See https://aka.ms/new-console-template for more information

(int x, int y) = ReadTwoInts();
Console.WriteLine(y == 1 ? x - 1 : x * (y - 1));

#region Read
static int ReadInt() => int.Parse(Console.ReadLine());
static (int x, int y) ReadTwoInts()
{
	var ints = ReadInts();
	return (ints[0], ints[1]);
}
static string ReadString() => Console.ReadLine();
static List<string> ReadStrings() => Console.ReadLine().Split(' ').ToList();
static List<int> ReadInts()
{
	List<string> strings = ReadStrings();
	List<int> ints = new();
	for (int i = 0; i < strings.Count; i++)
	{
		ints.Add(int.Parse(strings[i]));
	}
	return ints;
}
#endregion


using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace CF1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] input = Console.ReadLine().Split(' ');
            int n = Int32.Parse(input[0]);
            int m = Int32.Parse(input[1]);
            if(m < 2)
            {
                Console.WriteLine(n - 1);
            }
            else
            {
                Console.WriteLine(n * (m - 1));
            }
            //Console.ReadLine();
        }
    }
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Numerics;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solution
{
    public void Solve()
    {
        int n = ReadInt();
        int m = ReadInt();

        if (m == 1)
            Write(n - 1);
        else
            Write(1L * n * (m - 1));
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUGLOCAL
        reader = new StreamReader("..\\..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("ysys.in");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            new Solution().Solve();
            //var thread = new Thread(new Solution().Solve, 1024 * 1024 * 1500);
            //thread.Start();
            //thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUGLOCAL
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0) currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++) matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++) ret[i][j] = matrix[j][i]; }
        return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++) lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array) writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++) ret[i] = new T(); return ret; }
    #endregion
}


// Problem: 1725A - Accumulation of Dominoes
// Author: Gusztav Szmolik

using System;

public class AccumulationOfDominoes {

    public static void Main () {
        string[] parts = Console.ReadLine ().Split ();
        int n = int.Parse (parts[0]);
        int m = int.Parse (parts[1]);
        long ans = (m > 1 ? (long)n*(m-1) : n-1);
        Console.WriteLine (ans);
    }
}


using System;
using System.Linq;
using System.Text;
using System.Numerics;
using static System.Console;
using System.Collections.Generic;

using static CompLib.Algorithm;

namespace ProblemSolving.cs
{
    class MainClass
    {
        const int Mod = (int) (1e9 + 7);
        const int Mod2 = 998244353;
        const int Def = (int) 1e9;
        const long INF = (long) 1e18;

        static long[] OneLongLine => ReadLine().Trim().Split(' ').Select(long.Parse).ToArray();
        static int[] OneIntLine => ReadLine().Trim().Split(' ').Select(int.Parse).ToArray();
        static int[] OneCharLine => ReadLine().Trim().ToCharArray().Select(v => v - '0').ToArray();
        static long OneLong => long.Parse(ReadLine().Trim());
        static int OneInt => int.Parse(ReadLine().Trim());
        static string OneString => ReadLine().Trim();

        static void Solve()
        {
            long[] line = OneLongLine;
            long n = line[0], m = line[1];

            if (m != 1)
            {
                WriteLine(n * (m - 1));
                return;
            }

            WriteLine(n - 1);

        }

        static bool Check(int[] arr)
        {
            var zero = arr.Count(v => v == 0);
            var one = arr.Count(v => v != 0);

            return one == 1 && zero == arr.Length - 1;
        }

        static void Main()
        {
            // int cases = OneInt;
            // while (cases-- > 0) Solve();

            Solve();
        }
    }

}

namespace CompLib
{
     public static class Algorithm
     {
         public static int LowerBound(int[] arr, int val)
         {
             int ng = -1;
             int ok = arr.Length;
             while (ok - ng > 1)
             {
                 int med = (ok + ng) / 2;
                 if (arr[med] >= val)
                 {
                     ok = med;
                 }
                 else
                 {
                     ng = med;
                 }
             }

             return ok;
         }

         public static int UpperBound(int[] arr, int val)
         {
             int ok = arr.Length;
             int ng = -1;
             while (ok - ng > 1)
             {
                 int med = (ok + ng) / 2;
                 if (arr[med] > val)
                 {
                     ok = med;
                 }
                 else
                 {
                     ng = med;
                 }
             }

             return ok;
         }
     }
}


using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace CF1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] input = Console.ReadLine().Split(' ');
            long n = Int64.Parse(input[0]);
            long m = Int64.Parse(input[1]);
            if(m < 2)
            {
                Console.WriteLine(n - 1);
            }
            else
            {
                Console.WriteLine(n * (m - 1));
            }
            Console.ReadLine();
        }
    }
}


using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;
using System.Numerics;

public class Test
{
    private static readonly Random r = new Random();
    public static void Main()
    {
    //    var t = GetInt();
       // for (int i = 0; i < t; i++)
            Solve();
    }

    public static bool DoesAttack(int x, int y, int a, int b) {
		// does a queen at (x, y) attack (a, b) ?
		return x == a || y == b || x+y == a+b || x-y == a-b;
	}

public static void Solve()
    {
        var arr = GetIntArray();
        int r = arr[0];
        int c = arr[1];
        long ans = c == 1 ? r-1 : (long)r * (c-1);
#if DEBUG
        Console.Write("Answer is --------------> \n");
#endif
        Console.WriteLine(ans);
    }

    public static int GetInt() => int.Parse(Console.ReadLine());
    public static long GetLong() => long.Parse(Console.ReadLine());

    public static int[] GetIntArray() => Console.ReadLine().Trim().Split(' ').Select(int.Parse).ToArray();
    public static long[] GetLongArray() => Console.ReadLine().Trim().Split(' ').Select(long.Parse).ToArray();

    public static int Gcd(int a, int b) => b == 0 ? a : Gcd(b, a % b);
    public static int Gcd(int[] n) => n.Aggregate((a, b) => Gcd(a, b));

    public static bool IsBitSet(long a, int bit)
    {
        return (a & (1L << bit)) != 0;
    }
}


// See https://aka.ms/new-console-template for more information

(int x, int y) = ReadTwoInts();
Console.WriteLine(y == 1 ? x - 1 : 1L * x * (y - 1));

#region Read
static int ReadInt() => int.Parse(Console.ReadLine());
static (int x, int y) ReadTwoInts()
{
	var ints = ReadInts();
	return (ints[0], ints[1]);
}
static string ReadString() => Console.ReadLine();
static List<string> ReadStrings() => Console.ReadLine().Split(' ').ToList();
static List<int> ReadInts()
{
	List<string> strings = ReadStrings();
	List<int> ints = new();
	for (int i = 0; i < strings.Count; i++)
	{
		ints.Add(int.Parse(strings[i]));
	}
	return ints;
}
#endregion


using System.Xml;
using System.ComponentModel.Design;
using System.Security.AccessControl;
using System.Globalization;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System;

namespace CodeForce
{
    class Program
    {
        static void Main(string[] args)
        {
            var arr = Console.ReadLine().Split(' ');
            var rows = Int32.Parse(arr[0]);
            var cols = Int32.Parse(arr[1]);
            Console.WriteLine(GetCount(rows,cols));

        }

        private static long GetCount(int rows, int cols)
        {
            if(rows == 1)
            {
                return 1;
            }
            var res = 1L;
            var maxPows = new int[rows+1];
            var cntArr = GetCntArr(cols);
            for(var i = 2;i <= rows;i++)
            {
                var tmp = i;
                for(var j=2;j<rows;j++)
                {
                    if(tmp<= rows/i)
                    {
                        tmp*=i;
                        if(maxPows[tmp] == 0)
                            maxPows[tmp] = j;
                    }
                    else
                    {
                        break;
                    }
                }

                if(maxPows[i] == 0)
                {
                    res+= cols;
                }
                else
                {
                    res+= cntArr[maxPows[i]];
                }

            }
            return res;
        }

        private static int[] GetCntArr(int n)
        {
            var cntArr = new int[21];

            for(var i =2;i<=20;i++)
            {
                var usedArr = new bool[n+1];
                for(var j = 1;j < i;j++)
                {
                    for(var k=1;k<=n;k++)
                    {
                        if(j*k % i == 0)
                        {
                            usedArr[j*k / i] = true;
                        }
                    }
                }
                for(var k=1;k<=n;k++)
                {
                    if(!usedArr[k]) cntArr[i]++;
                }
            }

            return cntArr;

        }

        private static int GetGCD(int num0, int num1)
        {
            if(num0 < num1)
            {
                var tmp = num0;
                num0 = num1;
                num1 = tmp;
            }
            while(num1!=0)
            {
                var tmp = num0% num1;
                num0 = num1;
                num1 = tmp;
            }
            return num0;
        }

        private static int BruteGetCount(int rows, int cols)
        {
            var set = new HashSet<int>();
            for(var i =1;i<=rows;i++)
            {
                var tmp = 1;
                for(var j=1;j<=cols;j++)
                {
                    tmp*=i;
                    set.Add(tmp);
                }
            }
            return set.Count;
        }

    }
}


// Online C# Editor for free
// Write, Edit and Run your C# code using C# Online Compiler

using System;

public class HelloWorld
{
    public static void Main(string[] args)
    {
        var arr = Console.ReadLine().Split(' ');

        int rows = Int32.Parse(arr[0]);
        int columns = Int32.Parse(arr[1]);
        //Console.WriteLine(rows);
       // Console.WriteLine(columns);
       Console.WriteLine(getUniqueNumbers(rows,columns));
    }

    public static int[] precalculate(int m){
        var cnt = new int[21];
        var vis = new bool[20000002];
        int c=0;
        for(int i=1;i<=20;++i){
            for(int j=1;j<=m;++j){
                if(!vis[i*j]){
                    vis[i*j]=true;
                    ++c;
                }
            }
            cnt[i]=c;
        }

        return cnt;
    }

    public static long getUniqueNumbers(int rows, int columns){
        var arr = precalculate(columns);

        long res=1;
        var vis = new bool[20000002];

        for(int i=2;i<=rows;++i){
            if(vis[i])continue;
            long j=i;
            int c=0;

            while(j<=(long)rows){
                vis[j]=true;
                j*=i;
                ++c;
            }

            res+= arr[c];
        }

        return res;
    }

}


using System.Xml;
using System.ComponentModel.Design;
using System.Security.AccessControl;
using System.Globalization;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System;

namespace CodeForce
{
    class Program
    {
        static void Main(string[] args)
        {
            var arr = Console.ReadLine().Split(' ');
            var rows = Int32.Parse(arr[0]);
            var cols = Int32.Parse(arr[1]);
            Console.WriteLine(GetCount(rows,cols));
        }

        private static long GetCount(int rows, int cols)
        {
            if(rows == 1)
            {
                return 1;
            }
            var res = 1L;
            var maxPows = new int[rows+1];
            var cntArr = GetCntArr(cols);
            for(var i = 2;i <= rows;i++)
            {
                var tmp = i;
                for(var j=2;j<rows;j++)
                {
                    if(tmp<= rows/i)
                    {
                        tmp*=i;
                        if(maxPows[tmp] == 0)
                            maxPows[tmp] = j;
                    }
                    else
                    {
                        break;
                    }
                }

                if(maxPows[i] == 0)
                {
                    res+= cols;
                }
                else
                {
                    res+= cntArr[maxPows[i]];
                }

            }
            return res;
        }

        private static int[] GetCntArr(int n)
        {
            var cntArr = new int[21];

            for(var i =2;i<=20;i++)
            {
                var usedArr = new bool[n+1];
                for(var j = 1;j < i;j++)
                {
                    var gcd = GetGCD(i,j);
                    var tmp = j/gcd;
                    for(var k=1;k<=n/tmp;k++)
                    {
                        usedArr[tmp*k / i] = true;
                    }
                }
                for(var k=1;k<=n;k++)
                {
                    if(!usedArr[k]) cntArr[i]++;
                }
            }

            return cntArr;

        }

        private static int GetGCD(int num0, int num1)
        {
            if(num0 < num1)
            {
                var tmp = num0;
                num0 = num1;
                num1 = tmp;
            }
            while(num1!=0)
            {
                var tmp = num0% num1;
                num0 = num1;
                num1 = tmp;
            }
            return num0;
        }

        private static int BruteGetCount(int rows, int cols)
        {
            var set = new HashSet<int>();
            for(var i =1;i<=rows;i++)
            {
                var tmp = 1;
                for(var j=1;j<=cols;j++)
                {
                    tmp*=i;
                    set.Add(tmp);
                }
            }
            return set.Count;
        }

    }
}


using System.Xml;
using System.ComponentModel.Design;
using System.Security.AccessControl;
using System.Globalization;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System;

namespace CodeForce
{
    class Program
    {
        static void Main(string[] args)
        {
            var arr = Console.ReadLine().Split(' ');
            var rows = Int32.Parse(arr[0]);
            var cols = Int32.Parse(arr[1]);
            Console.WriteLine(GetCount(rows,cols));
        }

        private static long GetCount(int rows, int cols)
        {
            if(rows == 1)
            {
                return 1;
            }
            var res = 1L;
            var maxPows = new int[rows+1];
            var cntArr = GetCntArr(cols);
            for(var i = 2;i <= rows;i++)
            {
                var tmp = i;
                for(var j=2;j<rows;j++)
                {
                    if(tmp<= rows/i)
                    {
                        tmp*=i;
                        if(maxPows[tmp] == 0)
                            maxPows[tmp] = j;
                    }
                    else
                    {
                        break;
                    }
                }

                if(maxPows[i] == 0)
                {
                    res+= cols;
                }
                else
                {
                    res+= cntArr[maxPows[i]];
                }

            }
            return res;
        }

        private static int[] GetCntArr(int n)
        {
            var cntArr = new int[21];

            for(var i =2;i<=20;i++)
            {
                var usedArr = new bool[n+1];
                for(var j = 1;j < i;j++)
                {
                    var gcd = GetGCD(i,j);
                    var tmp = i/gcd;
                    for(var k=1;k<=n/tmp;k++)
                    {
                        usedArr[tmp*k / i] = true;
                    }
                }
                for(var k=1;k<=n;k++)
                {
                    if(!usedArr[k]) cntArr[i]++;
                }
            }

            return cntArr;

        }

        private static int GetGCD(int num0, int num1)
        {
            if(num0 < num1)
            {
                var tmp = num0;
                num0 = num1;
                num1 = tmp;
            }
            while(num1!=0)
            {
                var tmp = num0% num1;
                num0 = num1;
                num1 = tmp;
            }
            return num0;
        }

        private static int BruteGetCount(int rows, int cols)
        {
            var set = new HashSet<int>();
            for(var i =1;i<=rows;i++)
            {
                var tmp = 1;
                for(var j=1;j<=cols;j++)
                {
                    tmp*=i;
                    set.Add(tmp);
                }
            }
            return set.Count;
        }

    }
}