cf1276C——单调性分析,思维

/*
假设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<<'
';
    cout<<R<<" "<<C<<'
';
    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