CF1705F Mark and the Online Exam 题解
首先这个东西可以转化成每次询问子集和:在开始询问一次全
解方程就可以得到
设
令
可以使用以下构造方式得到
- 将长度为
2f_n+2^n-1 的序列分成长度为f_n,f_n,2^n-1 的三块; - 询问第二块中
1 的个数,记作c=\operatorname{query}(\{k\mid f_n+1\le k\le 2f_n\}) ; - 对所有
1\le i<2^n ,询问q_{n,i}\cup\{f_n+k\mid k\in q_{n,i}\}\cup\{2f_n+i\} 与q_{n,i}\cup\{f_n+k\mid k\notin q_{n,i}\} ,不妨设两次询问的结果分别为a=\operatorname{query}(q_{n,i})+\operatorname{query}(\{f_n+k\mid k\in q_{n,i}\})+\operatorname{query}(\{2f_n+i\}) 和b=\operatorname{query}(q_{n,i})+(c-\operatorname{query}(\{f_n+k\mid k\in q_{n,i}\})) ,则有: -
- 询问整个序列中
1 的个数。
于是我们就在
使用归纳法不难证明
本题中
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int kN = 1001;
int n, c0;
int Q(string s) {
s = s.substr(0, n);
int l = count(s.begin(), s.end(), 'T'), v;
cout << s << endl;
cin >> v;
return (l - (c0 - v)) / 2;
}
vector<string> G(int k) {
if (k == 0) {
return {"T"};
}
vector<string> l = G(k - 1);
int n = l[0].size();
vector<string> p;
string _ = string(l.size() - 1, 'F');
for (int i = 0; i < l.size() - 1; ++i) {
_[i] = 'T';
p.push_back(l[i] + l[i] + _);
_[i] = 'F';
string _l;
for (char &ch : l[i]) {
_l += 'T' + 'F' - ch;
}
p.push_back(l[i] + _l + _);
}
p.push_back(string(n, 'F') + string(n, 'T') + _);
p.push_back(string(n * 2 + l.size() - 1, 'T'));
return p;
}
string C(int k, vector<int> &q) {
if (k == 0) {
return q[0] ? "T" : "F";
}
vector<int> lq, rq;
int c = q[q.size() - 2];
string ans, t;
for (int i = 0; i + 2 < q.size(); i += 2) {
int a = q[i], b = q[i + 1];
lq.push_back((a + b - c) / 2);
rq.push_back((a - b + c) / 2);
t += "FT"[(a + b - c) & 1];
}
rq.push_back(c);
lq.push_back(q.back() - c - count(t.begin(), t.end(), 'T'));
return C(k - 1, lq) + C(k - 1, rq) + t;
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0);
cin >> n;
cout << string(n, 'F') << endl;
cin >> c0;
vector<string> ql = G(8);
vector<int> sl;
for (string i : ql) {
sl.push_back(Q(i));
}
Q(C(8, sl));
return 0;
}