Problem: You are given n integers. You need to choose a subset and put the chosen numbers in a beautiful rectangle (rectangular matrix). Each chosen number should occupy one of its rectangle cells, each cell must be filled with exactly one chosen number. Some of the n numbers may not be chosen.

A rectangle (rectangular matrix) is called beautiful if in each row and in each column all values are different.

What is the largest (by the total number of cells) beautiful rectangle you can construct? Print the rectangle itself.

Input

The first line contains n (1 ≤ n ≤ 4⋅10^5). The second line contains n integers (1 ≤ a_i ≤ 10^9).

Output

In the first line print x (1 ≤ x ≤ n) — the total number of cells of the required maximum beautiful rectangle. In the second line print p and q (p ⋅ q=x): its sizes. In the next p lines print the required rectangle itself. If there are several answers, print any.

Examples

Input


12
3 1 4 1 5 9 2 6 5 3 5 8


Output


12
3 4
1 2 3 5
3 1 5 4
5 6 8 9


Input


5
1 1 1 1 1


Output


1
1 1
1

Solution (in JAVA):

Solution:
/**
 * BaZ :D
 */
import java.util.*;
import java.io.*;
import static java.lang.Math.*;

public class ACMIND
{
    static FastReader scan;
    static PrintWriter pw;
    static long MOD = 1_000_000_007 ;
    static long INF = 1_000_000_000_000_000_000L;
    static long inf = 2_000_000_000;
    public static void main(String[] args) {
        new Thread(null,null,"BaZ",1<<27)
        {
            public void run()
            {
                try
                {
                    solve();
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        }.start();
    }

    static Pair arr[];
    static int pref[];
    static int sz;
    static void solve() throws IOException
    {
        scan = new FastReader();
        pw = new PrintWriter(System.out,true);
        StringBuilder sb = new StringBuilder();
        int n = ni();
        Map<Integer, Integer> freq = new HashMap<>();
        for(int i=0;i<n;++i) {
            add(freq, ni());
        }
        sz = freq.size();
        arr = new Pair[sz];
        pref = new int[sz];
        int idx = 0;
        for(Map.Entry<Integer, Integer> e : freq.entrySet()) {
            arr[idx++] = new Pair(e.getValue(), e.getKey());
        }
        Arrays.sort(arr);
        for(int i=0;i<sz;++i) {
            pref[i] = arr[i].x;
            if(i>0) {
                pref[i]+=pref[i-1];
            }
        }
        int max = 0, len = -1;
        for(int i=1;i<=n;++i) {
            int sum = calcSum(i);
            if(sum/i >= i) {
                if(i*(sum/i) > max) {
                    max = i*(sum/i);
                    len = i;
                }
            }
        }
        int ROW = len, COL = calcSum(len)/len;
        pl(ROW*COL);
        pl(ROW+" "+COL);
        int ans[][] = new int[ROW][COL];
        for(int i=0;i<ROW;++i) {
            Arrays.fill(ans[i], -1);
        }
        ArrayList<Integer> nums = new ArrayList<>();
        ArrayList<Pair> pairs = new ArrayList<>();
        int sum = 0;
        for(Pair p : arr) {
            int lim = min(len, p.x);
            lim = min(lim, ROW*COL - sum);
            if(lim>0) {
                pairs.add(new Pair(lim, p.y));
                sum+=lim;
            }
            else {
                break;
            }
        }
        Collections.sort(pairs);
        Collections.reverse(pairs);
        for(Pair p : pairs) {
            for(int i=0;i<p.x;++i) {
                nums.add(p.y);
            }
        }
        //pa("nums", nums);
        idx = 0;
        int currx = 0, curry = 0;
        while(idx<ROW*COL) {
            if(ans[currx][curry] != -1) {
                currx = (currx+1)%ROW;
                continue;
            }
            ans[currx][curry] = nums.get(idx++);
            currx = (currx+1)%ROW;
            curry = (curry+1)%COL;
        }
        for(int i=0;i<ROW;++i) {
            for(int j=0;j<COL;++j) {
                p(ans[i][j]);
            }
            pl();
        }
        pw.flush();
        pw.close();
    }
    static int calcSum(int k) {
        int idx;
        if(arr[0].x>k) {
            idx = -1;
        }
        else {
            int low = 0, high = sz-1, ans = 0, mid;
            while(low<=high) {
                mid = (low+high)>>1;
                if(arr[mid].x <= k) {
                    ans = mid;
                    low = ++mid;
                }
                else {
                    high = --mid;
                }
            }
            idx = ans;
        }
        return (sz - 1 - idx) * k + (idx>=0 ? pref[idx] : 0);
    }
    static class Pair implements Comparable<Pair>
    {
        int x,y;
        Pair(int x,int y)
        {
            this.x=x;
            this.y=y;
        }
        public int compareTo(Pair other)
        {
            if(this.x!=other.x)
                return this.x-other.x;
            return this.y-other.y;
        }
        public String toString()
        {
            return "("+x+","+y+")";
        }
    }
    static void add(Map<Integer,Integer> map,int key)
    {
        Integer val = map.get(key);
        if(val==null)
            map.put(key,1);
        else map.put(key,val+1);
    }
    static int ni() throws IOException
    {
        return scan.nextInt();
    }
    static long nl() throws IOException
    {
        return scan.nextLong();
    }
    static double nd() throws IOException
    {
        return scan.nextDouble();
    }
    static void pl()
    {
        pw.println();
    }
    static void p(Object o)
    {
        pw.print(o+" ");
    }
    static void pl(Object o)
    {
        pw.println(o);
    }
    static void psb(StringBuilder sb)
    {
        pw.print(sb);
    }
    static void pa(String arrayName, Object arr[])
    {
        pl(arrayName+" : ");
        for(Object o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, int arr[])
    {
        pl(arrayName+" : ");
        for(int o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, long arr[])
    {
        pl(arrayName+" : ");
        for(long o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, double arr[])
    {
        pl(arrayName+" : ");
        for(double o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, char arr[])
    {
        pl(arrayName+" : ");
        for(char o : arr)
            p(o);
        pl();
    }
    static void pa(String listName, List list)
    {
        pl(listName+" : ");
        for(Object o : list)
            p(o);
        pl();
    }
    static void pa(String arrayName, Object[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(Object o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, int[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(int o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, long[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(long o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, char[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(char o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, double[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(double o : arr[i])
                p(o);
            pl();
        }
    }
    static class FastReader {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public FastReader() {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public FastReader(String file_name) throws IOException {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException {
            byte[] buf = new byte[1000000];
            int cnt = 0, c;
            while ((c = read()) != -1) {
                if (c == '\n') break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException {
            int ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do {
                ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        public long nextLong() throws IOException {
            long ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do {
                ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        public double nextDouble() throws IOException {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do {
                ret = ret * 10 + c - '0';
            } while ((c = read()) >= '0' && c <= '9');
            if (c == '.') while ((c = read()) >= '0' && c <= '9') ret += (c - '0') / (div *= 10);
            if (neg) return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1) buffer[0] = -1;
        }

        private byte read() throws IOException {
            if (bufferPointer == bytesRead) fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException {
            if (din == null) return;
            din.close();
        }
    }
}