/* 假设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 */
来源:https://www.cnblogs.com/zsben991126/p/12111373.html