题解:
本来这个题目不准备写题解了的,因为这个确实不是很难,但是我wa了很多次之后,发现还是有写的必要。
这个题目首先求出p和q,这个不是很难求,就是统计每一个数字的数量,然后排序一下,求出每一个宽 x 可以放进去的最多的数量。
求出 p q之后就是构造一个解即可。
但是这个构造要注意 一定是要 先构造小的!!!!
这个是为什么呢?
就看看3 5 感性理解一下吧
1 4 7 10 13
14 2 5 8 11
12 15 3 6 9
5 3
1 6 11
12 2 7
8 13 3
4 9 14
15 5 10
对于第二个 5和6 10和11是排在一块的,而对于第一个则没有这样的情况。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5+10;
typedef long long ll;
int a[maxn],v[maxn],num[maxn],val[maxn],sum[maxn],c[maxn];
map<int,int>mp[maxn];
bool cmp(int a,int b){
return num[a]>num[b];
}
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &v[i]);
a[i] = v[i];
c[i]=i;
}
sort(v + 1, v + 1 + n);
int len = unique(v + 1, v + 1 + n) - v - 1;
for (int i = 1; i <= n; i++) {
int pos = lower_bound(v + 1, v + 1 + len, a[i]) - v;
num[pos]++, val[pos] = num[pos];
}
sort(val + 1, val + 1 + len);
for (int i = 1; i <= len; i++) {
int x = lower_bound(val + 1, val + 1 + len, i) - val;
// printf("i=%d x=%d val=%d
",i,x,val[i]);
sum[i] = sum[i - 1] + len - x + 1;
}
int p = 1, q = 1, maxs = 0;
for (int i = 1; i <= sqrt(n); i++) {
int res = sum[i] / i * i;
if(sum[i]/i<i) continue;
// printf("i=%d sum=%d res=%d
",i,sum[i],res);
if (res > maxs) {
maxs = res;
p = i;
q = sum[i] / i;
}
}
// printf("p=%d q=%d
",p,q);
int sx = 0, sy = 0,now = 0;
sort(c+1,c+1+len,cmp);
for (int i = 1; i <= len; i++) {
int id = c[i];
for (int j = 1; j <= min(p, num[id]); j++) {
mp[sx][sy] = v[id];
sy=(sy+1)%q, sx=(sx+1)%p;
if(!sx){
++now;
sx = 0,sy = now;
}
}
}
printf("%lld
",1ll*p*q);
printf("%d %d
",p,q);
for(int i=0;i<p;i++){
for(int j=0;j<q;j++){
printf("%d ",mp[i][j]);
}
printf("
");
}
}