POJ 2010: Moo University - Financial Aid
概要
コストa[i]と評価値s[i]の組の列がある.
この中から,N(奇数)個の要素をコストの合計がFを超えないように選び,メディアンを最大化したい.
解法
メディアンはソートしたときの中央値であり,中央の値以外には影響をうけないことを利用する.
N = 2K + 1とする.
コストについてソート.
あるインデックスiについて,iより小さいインデックスの中からK個選ぶときのコストの最小値を計算.iより大きいインデックスについても同様に計算.この計算は,PriorityQueueを用いることでO(N log N)時間で事前に計算できる.
上記二つの値の合計とi番目のコストの合計がF以下であれば,答えをs[i]に更新する.
int N, C, F, K; pair<int, int> c[100010]; ll l[100010], u[100010]; const ll INF = 1000000000000; void calc(ll *a){ ll s = 0LL; priority_queue<int> Q; for(int i = 0; i < K; ++i){ Q.push(c[i].second); s += c[i].second; a[i] = INF; } for(int i = K; i < C; ++i){ a[i] = s; if(Q.top() > c[i].second){ s += c[i].second - Q.top(); Q.pop(); Q.push(c[i].second); } } } int main(){ scanf("%d%d%d", &N, &C, &F); for(int i = 0; i < C; ++i){ int s, a; scanf("%d%d", &s, &a); c[i] = make_pair(s, a); } sort(c, c+C); K = N / 2; calc(l); reverse(c, c+C); calc(u); reverse(u, u+C); reverse(c, c+C); int res = -1; for(int i = 0; i < C; ++i) if(l[i] + u[i] + c[i].second <= F) res = c[i].first; printf("%d\n", res); return 0; }