SRM 251 DIV1 Hard MusicCompilation
問題
アーティストの名前とその人の曲の数artistsがいくつか与えられる。
各アーティストがその人の曲の数だけ出てくるリストであって、
let d v = sum. map (maybe 0 succ. uncurry elemIndex). zip v. tail. tails$ v
と定義されるd(x)を最大化する必要がある。
そのとき、辞書順最小のものを求めよ
解答
最大化はgreedyで、「最初にcountが大きい方から埋める」「そのあとは、countが大きい順に、また前との距離が大きい順に」やる。これはpriority_queueで上手く書ける。
それで辞書順greedyやった。
Editorialや他の人の解答によると、もっと簡単に規則的に生成できるようだ。
基本的なgreedyと、あとはどうでもいいからソートしてやる!のような感じで。
コメント
コード汚いし遅すぎるし…きれいな解答書きたい
コード
#include <string> #include <vector> #include <algorithm> #include <queue> #include <sstream> #define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i)) #define all(o) (o).begin(), (o).end() #define pb(x) push_back(x) #define mp(x,y) make_pair((x),(y)) using namespace std; typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pair<int,int> > vpii; typedef vector<string> vs; struct MusicCompilation { int greedy(int tt, const vi& prev, const vi& count) { int n = prev.size(); vpii v; rep(i, n) v.pb(mp(count[i], i)); sort(all(v), greater<pii>()); priority_queue<pii> q; int r = 0, t = tt; rep(i, v.size()) if(v[i].first) { if(prev[v[i].second] == -1) { ++ t; if(v[i].first > 1) q.push(mp(v[i].first - 1, -(t - 1))); } else if(v[i].first) q.push(mp(v[i].first, - prev[v[i].second])); } while(!q.empty()) { pii p = q.top(); q.pop(); r += t - -p.second; ++ t; if(p.first > 1) q.push(mp(p.first - 1, - (t - 1))); } return r; } vector <string> makeCompilation(vector <string> artists) { int n = artists.size(); if(n == 0) return vs(); vs name(n); vi count(n); int sum = 0; vector<pair<string,int> > v; rep(i, n) { stringstream ss(artists[i]); string s; int x; ss >> s >> x; v.pb(mp(s,x)); sum += x; } sort(all(v)); rep(i, n) name[i] = v[i].first, count[i] = v[i].second; int mx = greedy(0, vi(n, -1), count); vs r; vi prev(n, -1); int prevsum = 0; rep(t, sum) { int mi = -1; rep(i, n) if(count[i] > 0) { int prevsum_t = prevsum; if(prev[i] != -1) prevsum_t += t - prev[i]; count[i] --; int prev_t = prev[i]; prev[i] = t; int x = prevsum_t + greedy(t+1, prev, count); if(x == mx) { mi = i; count[i] ++; prev[i] = prev_t; break; } count[i] ++; prev[i] = prev_t; } if(prev[mi] != -1)prevsum += t - prev[mi]; prev[mi] = t; count[mi] --; r.pb(name[mi]); } return r; } };