/*
假设row<=col,先求出面积最大的矩阵的(row,col),再去考虑往里面填数
当前行是row时,这个矩阵里最多容纳同一个数row次,
将数统计之后,按出现次数排序,再从大到小枚举row,通过每个数的出现次数,算出此时最大的col
记录下最大的row和col,然后进行填数,填数时同一个数斜着填即可
*/
#include<bits/stdc++.h>
using namespace std;
#define N 400005
#define ll long long
int sum[N],n,a[N],cnt;
map<int,int>mp;
struct Node{int v,cnt;}p[N];
int cmp(Node &a,Node &b){return a.cnt<b.cnt;}
int bin_find(int row){//找到最后一个<=row的位置
int L=0,R=cnt,ans=0,mid;
while(L<=R){
mid=L+R>>1;
if(p[mid].cnt<=row)
ans=mid,L=mid+1;
else R=mid-1;
}
return ans;
}
int ma[N],R,C;
inline int id(int i,int j){return C*(i-1)+j;}
stack<int>stk;
void solve(){
for(int i=1;i<=cnt;i++)
for(int j=1;j<=min(p[i].cnt,R);j++)
stk.push(p[i].v);
for(int k=1;k<=C;k++){
int i=1,j=k;
while(i<=R && j<=C){
ma[id(i,j)]=stk.top();
stk.pop();
++i,++j;
if(i>R)break;
if(j>C)j-=C;
}
}
cout<<R*C<<'\n';
cout<<R<<" "<<C<<'\n';
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++)
cout<<ma[id(i,j)]<<" ";
puts("");
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
mp[a[i]]++;
}
for(auto x:mp){
p[++cnt].v=x.first;
p[cnt].cnt=x.second;
}
sort(p+1,p+1+cnt,cmp);
for(int i=1;i<=cnt;i++)
sum[i]=sum[i-1]+p[i].cnt;
int ansr=0,ansc=0;
int row=(int)sqrt(n);
while(row){
int p=bin_find(row);
int num=sum[p]+row*(cnt-p);
int col=num/row;
if(col>=row && ansr*ansc<col*row){
ansr=row;ansc=col;
}
row--;
}
R=ansr,C=ansc;
solve();//填数
}
/*
10000000002
21000000000
02100000000
00210000000
00021000000
12000
01200
00120
00012
20001
*/