kmjp's blog

競技プログラミング参加記です

yukicoder : No.850 企業コンテスト2位

シンプルな設定で良かったです。
https://yukicoder.me/problems/no/850

問題

N人の人がいて、1~N位の順位が付いた。
ある2人の順位を問い合わせたとき、どちらの順位が上か答えてくれるクエリがある。
このクエリを334回まで用いて、2位の人を特定せよ。

解法

1位を特定しようとすると、(N-1)回問い合わせが必須である。
Nの上限が300なので、残り35回以下で2位を特定することを考える。

2位は1位以外に負けないので、言い換えればどこかで敗者がいると、1位の人に負けた人の中に2位の人がいる。
そこで、まずN名で2分木型のトーナメントを組ませ1位を特定する。
その際、各人が誰に負けたかを覚えておこう。

トーナメントを終え1位が確定すると、1位に負けた人はlogN人しかいないはずなので、その中での最上位の人を探せばよい。

int N;

int lose[333];
int ask(int x,int y) {
	int r;
	cout<<"? "<<x<<" "<<y<<endl;
	cin>>r;
	return r;
}

int ans(int a) {
	cout<<"! "<<a<<endl;
	exit(0);
}

int win(int L,int R) {
	if(L+1>=R) return L;
	int M=(L+R)/2;
	
	int x=win(L,M);
	int y=win(M,R);
	if(ask(x,y)==x) {
		lose[y]=x;
		return x;
	}
	else {
		lose[x]=y;
		return y;
	}
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	x=win(1,N+1);
	
	vector<int> V;
	for(i=1;i<=N;i++) if(lose[i]==x) V.push_back(i);
	
	int cur=V[0];
	for(i=1;i<V.size();i++) cur=ask(cur,V[i]);
	ans(cur);
	
}

まとめ

クエリ上限が400とか言われたら却って迷ったかも。