[IOI2018]组合动作 题解

传送门 LOJ2863

果然签到题就是好玩

首先我们可以猜2次来猜出第一个字符是什么,后面的串就和这个字符没关系了。

假设剩下的三个字符是tmp[0]tmp[1]tmp[2],目前已知答案串的长度为 i 1 i-1 的前缀是ans。考虑第 i i 位( i n 1 i\leq n-1 ),我们可以在ans串后面接上一个字符然后press来检查有没有获得更多的金币,但是这样的话你总共要press大约 3 n 3n 次,不够理想。

我们可以设计一种方法来一次就获得S[i]是什么字符,那就需要设计一个串p使得对于不同的S[i]press(p)的返回值不同。我们可以令p=ans+tmp[0]+ans+tmp[1]+tmp[0]+ans+tmp[1]+tmp[1]+ans+tmp[1]+tmp[2],那么如果press(p)返回的是 i 1 i-1 就说明第 i i 位是tmp[2],如果返回值是 i i 就说明第 i i 位是tmp[0],否则就是tmp[1]

对于最后一位,再press两下就行了。

#include "combo.h"
#include <string>

char tmp[3];
std::string guess_sequence(int n) {
	char first;
    if (press("AB")) {
		if (press("A")) first = 'A', tmp[0] = 'B', tmp[1] = 'X', tmp[2] = 'Y';
		else first = 'B', tmp[0] = 'A', tmp[1] = 'X', tmp[2] = 'Y';
	} else {
		if (press("X")) first = 'X', tmp[0] = 'A', tmp[1] = 'B', tmp[2] = 'Y';
		else first = 'Y', tmp[0] = 'A', tmp[1] = 'B', tmp[2] = 'X';
	}
	std::string ans; ans += first;
	if (n == 1) return ans;
	for (int i = 2; i < n; ++i) {
		std::string p = ans + tmp[0] + ans + tmp[1] + tmp[0] + ans + tmp[1] + tmp[1] + ans + tmp[1] + tmp[2];
		int coin = press(p);
		if (coin == i - 1) ans += tmp[2];
		else if (coin == i) ans += tmp[0];
		else ans += tmp[1];
	}
	if (press(ans + tmp[0]) == n) ans += tmp[0];
	else if (press(ans + tmp[1]) == n) ans += tmp[1];
	else ans += tmp[2];
	return ans;
}

猜你喜欢

转载自blog.csdn.net/qq_39677783/article/details/86899807