Codeforces 1276C/1277F Beautiful Rectangle (构造)
題目鏈接
http://codeforces.com/contest/1276/problem/C
題解
嗯,比賽結束前3min想到做法然后rush不出來了……比賽結束后又寫了15min才過……
以下是我的做法:
設最優解的行數和列數分別是\(R\)和\(C\), 不妨設\(R\le C\). 那么顯然對于每個數我們只能選不超過\(R\)個。
考慮將所有數按出現次數從大到小排序,枚舉\(R\), 求出可用的數的個數,設為\(cnt\), 那么顯然\(C\le \frac{cnt}{R}\).
我們可以通過構造的方式證明,\(C\)可以取到\(\lfloor\frac{cnt}{R}\rfloor\).
下面為了方便默認\(cnt\)已經去掉了\(\mod R\)的余數。
把所有數按出現次數從大到小的順序依次連成一個序列(一個數出現了多少次就復制多少個)。那么對于任意\(0\le x\lt R,0\le y\lt C\), 我們將序列的第\((xC+y)\)個數放到矩陣的第\(y\)行第\((x+y)\mod C\)列, 其中序列和矩陣的坐標均從\(0\)開始。這樣我們可以證明一定滿足條件。
舉例解釋一下: 假設有\(12\)個數排成\(3\times 4\)的矩陣,那么矩陣中每個數在原序列中的下標為:
正確性證明: 對于同一種數,顯然它在序列中的位置滿足要么所有的\(x\)都相同,要么是\(x\)的一個后綴和\((x+1)\)的一段前綴拼起來,且長度不超過\(R\).
如果是前者,正確性顯然。如果是后者,唯一可能影響正確性的情況就是\(x\)后綴部分的某個數和\(y\)前綴部分的某個數放到了同一列上。
顯然這種情況只有出現次數等于\(R\)時才會出現(因為每次是整體右移一列),而因為我們是按出現次數從大到小排序構造排列,所以出現次數為\(R\)的都被放到了序列最前面,此時因為前面已經放了的個數都是\(R\)的倍數,所以這一個一定從第\(0\)行開始放,屬于第一種情況。因此第二種情況不會出現此問題,證畢。
故枚舉每個\(R\), 求出對應的\(C\), 取最大值,再對取到最大值的\(R\)執行上述構造算法即可。
時間復雜度\(O(n\log n)\), 瓶頸在于離散化后統計每個數出現多少次。
代碼
由于是很不冷靜地rush出來的所以寫得比較亂……
#include<bits/stdc++.h> #define llong long long #define pii pair<int,int> #define mkpr make_pair using namespace std;inline int read() {int w=1,s=0;char ch=getchar();while(!isdigit(ch)) {if(ch=='-')w=-1;ch=getchar();}while(isdigit(ch)) {s=s*10+ch-'0';ch=getchar();}return w*s; }const int N = 1e6; pii num[N+3]; int cans[N+3]; int fans[N+3]; vector<int> disc; int a[N+3]; int n,wei;int gcd(int x,int y) {return y==0?x:gcd(y,x%y);}int main() {scanf("%d",&n);for(int i=1; i<=n; i++) scanf("%d",&a[i]),disc.push_back(a[i]);sort(disc.begin(),disc.end()); disc.erase(unique(disc.begin(),disc.end()),disc.end());for(int i=1; i<=n; i++) a[i] = lower_bound(disc.begin(),disc.end(),a[i])-disc.begin()+1;for(int i=1; i<=n; i++) num[i].second = i;for(int i=1; i<=n; i++) num[a[i]].first++;sort(num+1,num+n+1);int l = 1,r = 0,cnt = 0,ans = 0,mxr = 1;for(int i=1; i<=n; i++){while(l<=n && num[l].first<i) {l++;}cnt += n-l+1;if(cnt/i<i) break;int cur = cnt/i*i;if(cur>ans) {ans = cur; mxr = i;}}int mxc = ans/mxr;printf("%d\n%d %d\n",ans,mxr,mxc);l = 1; while(l<=n && num[l].first<1) {l++;}int x = 0,y = 0; wei = 0;for(int i=n; i>=l; i--){int cnt = min(num[i].first,mxr);for(int j=1; j<=cnt&&wei<=ans; j++,wei++){cans[x*mxc+(x+y)%mxc] = disc[num[i].second-1]; x++; if(x==mxr) {y++,x=0;}}}for(int i=0; i<ans; i++){printf("%d ",cans[i]);if((i+1)%mxc==0) puts("");}return 0; }總結
以上是生活随笔為你收集整理的Codeforces 1276C/1277F Beautiful Rectangle (构造)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Codeforces 1276C/127
- 下一篇: UOJ #268 BZOJ 4732 [