Codeforces Round #100 C : New Year Snowmen
問題概要
長さN(<10^5)の整数列が与えられる。互いにことなる3つを選んでひとつのグループを構成することができる。最大でいくつのグループができるかを求め、実際に復元する問題。
解法
いくつできるかを二分探索で求め、その答えを利用して復元すれば良い。heapを使ってgreedyにやってもできるらしい(計算量は多分一緒?かしこいheap使えば計算量落ちるかも)
acceptされたコード
計算量O(N * log N)。以下の実装はmapを直接使ってるのでさらにlogがかかる。
#include <cstdio> #include <algorithm> #include <map> using namespace std; const int MAX_N = 1e5; int N; int as[MAX_N]; int xs[MAX_N][3]; map<int, int> dict; bool check(int x){ int cnt = 0; for(map<int,int>::iterator itr=dict.begin(); itr!=dict.end(); itr++){ cnt += min(x, itr->second); } return cnt >= 3*x; } void solve(){ sort(as, as + N); for(int i=0; i<N; i++){ dict[as[i]]++; } int low = 0, high = N; while(high - low > 1){ int mid = (high + low) / 2; if(check(mid)){ low = mid; } else{ high = mid; } } int ans = low; printf("%d\n", low); map<int,int> use; int p = 0, q = 0; for(int i=0; i<N; i++){ if(use[as[i]] < ans){ use[as[i]]++; xs[p++][q] = as[i]; if(p==ans){ q++; p = 0; if(q == 3){ break; } } } } for(int i=0; i<ans; i++){ sort(xs[i], xs[i]+3); printf("%d %d %d\n", xs[i][2], xs[i][1], xs[i][0]); } } int main(){ scanf("%d", &N); for(int i=0; i<N; i++){ scanf("%d", as+i); } solve(); return 0; }