CodeForces 1705F Mark and the Online Exam
看到询问次数接近 \(n\),考虑将 \(n\) 分成多组,每组都以较少的期望询问次数解决。
先询问一次全 F
,接下来的询问就能确定若干个位置的 T
个数。考虑每次从答案未确定的问题集合中随 \(4\) 个(如果集合大小 \(< 4\) 就暴力),先问这 \(4\) 个中 T
的个数,如果结果为 \(0\) 或 \(4\) 就说明全是 F/T
。否则再问前两个,如果结果为 \(0\) 或 \(2\) 就说明都是 F/T
;否则它们是 TF
或 FT
,那我们得到了其中一个是另一个的取反,能解决一个。对于后两个 T
的个数可以通过前两次询问的结果算出,类似地分类讨论即可。
接下来我们计算期望次数(只考虑 F
和 T
等概率出现的情况,因为其中一个更多时期望次数显然更少):
- \(\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;
}