Lilliput Steps

小さな一歩から着実に. 数学やプログラミングのことを書きます.

JOI春合宿 2009-day2 Contest

問題文 : コンテスト

解法 :
まずは, 国C の得点を最大化する. これは, 得点が不明なチームの降順に点数を2 つ(若しくは足りない分)取れば良い.

次に, 国C の順位を最大化する. これは, 二分探索を行なって位置を定めてやれば良い. (X 位になれる -> X + 1 位にもなれる.)

まずは, 自分より点数が高いチームがX - 1 個あると仮定し, あとはupper_bound などを使って自分より順位を低くしようと努力する. 努力をしても強いチームがいた場合, 勝ち目が無いのでX 位にはなれない.

コード :

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

int N, C;
int team[3000], snum[3000];

bool ok(int rank, vector<int> solo, vector<int> none)
{
	int p = 1;
	
	for (int i = 0; i < N; i++){
		if (snum[i] == 2 && team[i] > team[C]) p++;
	}
	
	if (p > rank) return (false);
	
	
	while (p != rank){
		if (solo.size() != 0){
			if (none.size() == solo.size()){
				solo.pop_back(); none.pop_back();
			}
			else {
				if (none[none.size() - 1] + none[none.size() - 2] > solo[solo.size() - 1] + none[none.size() - 1]){
					none.pop_back(); none.pop_back();
				}
				else {
					solo.pop_back(); none.pop_back();
				}
			}
		}
		else {
			none.pop_back(); none.pop_back();
		}
		p++;
	}
	
	vector<int>::iterator it;
	while (solo.size() || none.size()){
		if (solo.size() != 0){
			if (none.size() == solo.size()){
				int a = upper_bound(solo.begin(), solo.end(), team[C] - none[none.size() - 1]) - solo.begin() - 1;
				int b = upper_bound(none.begin(), none.end(), team[C] - solo[solo.size() - 1]) - none.begin() - 1;
				//printf("%d %d\n", a, b);
				if (a >= 0){
					none.pop_back(); solo.erase(solo.begin() + a, solo.begin() + a + 1);
				}
				else {
					if (b < 0) return (false);
					solo.pop_back(); none.erase(none.begin() + b, none.begin() + b + 1);
				}
			}
			else {
				int a = upper_bound(solo.begin(), solo.end(), team[C] - none[none.size() - 1]) - solo.begin() - 1;
				int b = upper_bound(none.begin(), none.end(), team[C] - solo[solo.size() - 1]) - none.begin() - 1;
				int c = upper_bound(none.begin(), none.end() - 1, team[C] - none[none.size() - 1]) - none.begin() - 1;
				//printf("%d %d %d\n", a, b, c);
				if (a >= 0){
					none.pop_back(); solo.erase(solo.begin() + a, solo.begin() + a + 1);
				}
				else if (b >= 0){
					solo.pop_back(); none.erase(none.begin() + b, none.begin() + b + 1);
				}
				else {
					if (c < 0) return (false);
					none.pop_back(); none.erase(none.begin() + c, none.begin() + c + 1);
				}
			}
		}
		else {
			int pos = upper_bound(none.begin(), none.end() - 1, team[C] - none[none.size() - 1]) - none.begin() - 1;
			//printf("%d\n", pos);
			if (pos < 0) return (false);
			it = none.begin() + pos;
			none.erase(it, it + 1); none.pop_back();
		}
	}
	
	return (true);
}

int main()
{
	vector<int> none;
	
	scanf("%d %d", &N, &C); --C;
	
	memset(team, 0, sizeof(team));
	memset(snum, 0, sizeof(snum));
	
	for (int i = 0; i < 2 * N; i++){
		int score, idx;
		scanf("%d %d", &score, &idx);
		if (idx){
			team[--idx] += score;
			snum[idx]++;
		}
		else none.push_back(score);
	}
	
	sort(none.begin(), none.end());
	
	while (snum[C] < 2){
		team[C] += none[none.size() - 1];
		snum[C]++;
		none.pop_back();
	}
	
	int zero = 0;
	int rank = 1;
	vector<int> solo;
	for (int i = 0; i < N; i++){
		if (snum[i] == 0) zero++;
		else if (snum[i] == 1 && team[i] > team[C]){
			team[i] += none[none.size() - 1];
			snum[i]++;
			none.pop_back();
			rank++;
		}
		else if (snum[i] == 1) solo.push_back(team[i]);
		else if (snum[i] == 2 && team[i] > team[C]) rank++;
	}
	
	sort(solo.begin(), solo.end());
	int left = rank, right = N;
	while (left != right){
		int center = (left + right) / 2;
		
		if (ok(center, solo, none)) right = center;
		else left = center + 1;
	}
	
	printf("%d\n", left);
	
	return (0);
}