AOJ1080 Everything Starts With Your Vote

問題リンク Everything Starts With Your Vote

  • 解法

上位K人の中に入れるお気に入りのキャラ数について2分探索して解きます。
キャラは人気度でソートしておきます。
need(X): 上位K人の中にお気に入りのキャラをX人食い込ませるために必要な最低投票数
というメソッドを用意します。
既に上位K人にX人以上の人数がいるときは0を返します。
さもなければ、上位K人の中に、超えなければいけないお気に入りでないキャラが1人以上いるはずです。その中で最も強いキャラをtargetとします。
targetより上位にいるお気に入りキャラがA人いたとするならば、targetより下位の中で上からX-A人のお気に入りキャラをtargetに勝たせなければなりません。勝たせるために必要な全投票数を返り値とします。

  • ソース
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

//Everything Starts With Your Vote
public class AOJ1080 {

	class R implements Comparable<R>{
		String s;
		int x;
		public R(String s, int x) {
			this.s = s;
			this.x = x;
		}
		int win(R r){
			return s.compareTo(r.s)<0?r.x-x:(r.x-x+1);
		}
		public int compareTo(R o) {
			return x!=o.x?o.x-x:s.compareTo(o.s);
		}
	}
	
	int N, M, K, L, B;
	R[] r;
	boolean[] fav;
	Set<String> fn;
	
	long need(int x){
		if(x<=B)return 0;
		int n = x-B, c = 0;
		int k = K-1;
		for(;;){
			if(fav[k])n++;
			else c++;
			if(c==x-B)break;
			k--;
		}
		R tar = r[k];
		long res = 0;
		for(int i=k+1;i<N&&0<n;i++){
			if(!fav[i])continue;
			n--;
			res+=r[i].win(tar);
		}
		return res;
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		fav = new boolean[100000];
		for(;;){
			N = sc.nextInt(); M = sc.nextInt(); K = sc.nextInt(); L = sc.nextInt();
			if((N|M|K|L)==0)break;
			r = new R[N];
			for(int i=0;i<N;i++)r[i]=new R(sc.next(), sc.nextInt());
			Arrays.sort(r);
			Arrays.fill(fav, false);
			fn = new HashSet<String>();
			for(int i=0;i<M;i++)fn.add(sc.next());
			B = 0;
			for(int i=0;i<N;i++){
				if(fn.contains(r[i].s)){
					fav[i] = true;
					if(i<K)B++;
				}
			}
			int left = B, right = Math.min(M, K);
			while(right-left>1){
				int m = (left+right)/2;
				if(L<need(m))right=m;
				else left=m;
			}
			System.out.println(need(right)<=L?right:left);
		}
	}
	
	public static void main(String[] args) {
		new AOJ1080().run();
	}
}