Codeforces 149 C. Division into Teams
問題
n人の人がいて、それぞれのスキルはa[i]である。
全員をちょうど二つのチームに振り分けたい。
チーム分けは、
- 人数の差が1以下
- チームの全員のスキルの和の差が、最も高いスキルを持つ人のスキル以下
という条件を満たすように行う。
正しいチームわけをどれか一通り出力せよ。
必ずそのようなチームわけがあることは保証されている。
制約条件
n≦10^5
1≦a[i]≦10^5
方針
まずはスキルを気にせずに、人数がだけ合うようにチームを分ける。
その後、スキルの合計の大きいチームの、最もスキルのある人と
スキルの合計の小さいチームの、最もスキルのない人を交換する。
この交換を条件が満たされるまで行い続ける。
最大値、最小値をO(log n)くらいの時間で知りたいので、
setを使えばよい。
ソースコード
int n; void run() { cin>>n; set<pi> a, b; int mx=0; ll as=0, bs=0; rep(i,n){ int t; cin>>t; mx=max(mx,t); if(i<n/2)a.insert(mp(t,i+1)), as+=t; else b.insert(mp(t,i+1)), bs+=t; } while(abs(as-bs)>mx){ set<pi>::iterator it; pi x, y; if(as>bs){ it=a.end(); it--; pi x=*it, y; a.erase(it); it=b.begin(); y=*it; b.erase(it); a.insert(y); b.insert(x); as+=y.first-x.first; bs+=x.first-y.first; } else{ it=a.begin(); pi x=*it, y; a.erase(it); it=b.end(); it--; y=*it; b.erase(it); a.insert(y); b.insert(x); as+=y.first-x.first; bs+=x.first-y.first; } } cout<<a.size()<<endl; fr(i,a)cout<<i->second<<" "; cout<<endl; cout<<b.size()<<endl; fr(i,b)cout<<i->second<<" "; cout<<endl; }