ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[构造] Codeforces 1276C/1278E Beautiful Rectangle

2020-03-01 12:57:52  阅读:219  来源: 互联网

标签:Beautiful 10 include int 1278E Codeforces row Col Row


题目大意

我们称一个矩阵是美丽的,当且仅当该这矩阵中不存在两个相同的数在同一列或在同一行。

给定 \(n\) 个数,要求你选出尽量多的数,使它们能够组成一个美丽的矩形。

注意,本题要求输出选出的数的个数与组成矩形大小和具体方案。

\(n\leq 4 \times 10^5\)

题解

想了好几天了,终于想出来了,果然是我太菜...

首先,可以想到,对于一个\(x\)行的矩形(令列数大于等于行数),如果有一个数出现了超过\(x\)次,是不可能将这个数全部填入这个矩形的,最多只能填\(x\)个,即斜着填,按下图的顺序。

那么我们用一个map维护每个数出现的次数,按出现的次数从大到小来填数,相同的数填在一起。为什么要按出现的次数从大到小来填呢?如果随便填的话,会被这组数据hack掉。

7
8 5 10 4 10 8 3

我的答案是

6
2 3
3 5 8
10 4 8

正确答案是

6
2 3
8 10 3
4 8 10

发现虽然是斜着填的,但两个8竟然在同一列。可以证明,按出现的次数从大到小来填数,就不会出现这样的情况。

然后我们就要先确定这个矩形有多少行,我们从\(1 \sim \sqrt n\)去枚举行数,假设当前枚举到的行数为\(Row\),那么对于每个数,我们最多取\(Row\)次,可以用前缀和+二分计算出我们总共能取的数的数量\(Cnt\),然后就可以计算出行数\(Col=\left\lfloor\frac{Cnt}{Row}\right\rfloor\times Row\),但是\(Col\)不能小于\(Row\),不然就不符合我们之前规定的列数大于等于行数。可以证明一定存在一种填法,能够填满这\(Row \times Col\)的矩形。

所以我们可以先把所有数按出现的次数排序,再用\(O\left(\sqrt nlogn\right)\)的时间枚举行数并计算出最大的矩形的大小,接着再用\(O(n)\)的时间去填数,最终的时间复杂度为\(O( nlogn + \sqrt nlogn +n)\)

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType &T){
    elemType X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    T=(w?-X:X);
}

struct Node{int Num,Cnt;};
map<int,int> Hash;
vector<Node> Com;
vector<int> Data;
vector<int> Mat[1000];

int Sum[400010];
int N,Row=0,Col=0,Total=0;

bool cmp(Node A,Node B){return A.Cnt>B.Cnt;}

inline int Judge(int row){
    int Pos=upper_bound(Data.begin(),Data.end(),row)-Data.begin()-1;
    int Res=(Sum[Pos]+((int)Data.size()-Pos-1)*row)/row*row;
    if(Res/row<row) return 0;
    return Res;
}

int CountY=0;

inline void Move(int &px,int &py){
    if(px==Row-1) ++CountY;
    if(px+1<Row && py+1<Col){++px;++py;return;}
    if(px+1>=Row && py+1<Col){px=0;py=CountY;return;}
    if(px+1<Row && py+1>=Col){py=0;++px;return;}
    if(px+1>=Row && py+1>=Col){px=0;py=CountY;return;}
    return;
}

inline void Maintain(){
    int px=0,py=0;
    for(RG i=1;i<=Col;++i)
        for(RG j=0;j<Row;++j)
            Mat[j].push_back(0);
    for(int i=0;i<(int)Com.size();++i){
        int Num=Com[i].Num,Cnt=min(Com[i].Cnt,Row);
        for(RG i=1;i<=Cnt;++i){
            Mat[px][py]=Num;
            Move(px,py);
        }
    }    
    for(RG i=0;i<Row;++i){
        for(RG j=0;j<Col;++j){
            printf("%d",Mat[i][j]);
            if(j<Col-1) printf(" ");
        }
        printf("\n");
    }
    return;
}

int main(){
    Read(N);
    for(RG i=1;i<=N;++i){
        int x;Read(x);
        ++Hash[x];
    }
    Data.push_back(-2147483647);
    for(auto it:Hash){
        Data.push_back(it.second);
        Com.push_back((Node){it.first,it.second});
    }
    sort(Com.begin(),Com.end(),cmp);
    sort(Data.begin(),Data.end());
    for(RG i=1;i<(int)Data.size();++i)
        Sum[i]=Sum[i-1]+Data[i];
    for(RG i=1;i*i<=N;++i){
        int temp=Judge(i);
        if(temp>Total){Total=temp;Row=i;}
    }
    Col=Total/Row;
    printf("%d\n%d %d\n",Total,Row,Col);
    Maintain();
    return 0;
}

标签:Beautiful,10,include,int,1278E,Codeforces,row,Col,Row
来源: https://www.cnblogs.com/AEMShana/p/12389152.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有