CodeForces 1705F Mark and the Online Exam

洛谷传送门

CodeForces 传送门

看到询问次数接近 \(n\),考虑将 \(n\) 分成多组,每组都以较少的期望询问次数解决。

先询问一次全 F,接下来的询问就能确定若干个位置的 T 个数。考虑每次从答案未确定的问题集合中随 \(4\) 个(如果集合大小 \(< 4\) 就暴力),先问这 \(4\) 个中 T 的个数,如果结果为 \(0\)\(4\) 就说明全是 F/T。否则再问前两个,如果结果为 \(0\)\(2\) 就说明都是 F/T;否则它们是 TFFT,那我们得到了其中一个是另一个的取反,能解决一个。对于后两个 T 的个数可以通过前两次询问的结果算出,类似地分类讨论即可。

接下来我们计算期望次数(只考虑 FT 等概率出现的情况,因为其中一个更多时期望次数显然更少):

  • \(\frac{1}{8}\) 概率一次询问解决 \(4\) 个。
  • \(\frac{1}{8}\) 概率两次询问解决 \(4\) 个。
  • \(\frac{1}{2}\) 概率两次询问解决 \(3\) 个。
  • \(\frac{1}{4}\) 概率两次询问解决 \(2\) 个。

写个 dp 可以得出期望询问次数约为 \(627\) 次,可以通过。

code
// LUOGU_RID: 99408009
/*

p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 1010;

int n, ans[maxn], nxt[maxn];
char s[maxn];

int ask() {
	printf("%s\n", s + 1);
	fflush(stdout);
	int x;
	scanf("%d", &x);
	if (x == n || x == -1) {
		exit(0);
	}
	return x;
}

void dfs(int x) {
	if (ans[x] >= 0) {
		return;
	}
	dfs(nxt[x]);
	ans[x] = (ans[nxt[x]] ^ 1);
}

void solve() {
	mems(ans, -1);
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		s[i] = 'F';
	}
	int num = ask();
	vector<int> vc;
	for (int i = 1; i <= n; ++i) {
		vc.pb(i);
	}
	while ((int)vc.size() >= 4) {
		shuffle(vc.begin(), vc.end(), default_random_engine(random_device()()));
		vector<int> nv;
		for (int i = 0; i < (int)vc.size() / 4; ++i) {
			vector<int> vv;
			for (int j = i * 4; j < i * 4 + 4; ++j) {
				vv.pb(vc[j]);
				s[vc[j]] = 'T';
			}
			int tres = ask() - num;
			for (int x : vv) {
				s[x] = 'F';
			}
			if (tres == 4 || tres == -4) {
				for (int x : vv) {
					ans[x] = (tres == 4);
				}
				continue;
			}
			int x = vv[0], y = vv[1];
			s[x] = s[y] = 'T';
			int res = ask() - num;
			s[x] = s[y] = 'F';
			if (res == 2) {
				ans[x] = ans[y] = 1;
			} else if (res == -2) {
				ans[x] = ans[y] = 0;
			} else {
				nxt[y] = x;
				nv.pb(x);
			}
			x = vv[2];
			y = vv[3];
			res = tres - res;
			if (res == 2) {
				ans[x] = ans[y] = 1;
			} else if (res == -2) {
				ans[x] = ans[y] = 0;
			} else {
				nxt[y] = x;
				nv.pb(x);
			}
		}
		for (int i = (int)vc.size() / 4 * 4; i < (int)vc.size(); ++i) {
			nv.pb(vc[i]);
		}
		vc = nv;
	}
	for (int x : vc) {
		s[x] = 'T';
		ans[x] = (ask() > num);
		s[x] = 'F';
	}
	for (int i = 1; i <= n; ++i) {
		if (ans[i] == -1) {
			dfs(i);
		}
	}
	for (int i = 1; i <= n; ++i) {
		s[i] = (ans[i] ? 'T' : 'F');
	}
	ask();
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}
posted @ 2023-01-12 15:41  zltzlt  阅读(25)  评论(0编辑  收藏  举报