CF1081F
设这个序列为 \(a\)。注意到连续操作 \([i,i]\) 两次所形成的序列要么是 \(a\),要么是除了 \(a_i\) 都翻转的序列。我们可以多随几次,总能碰到第二种情况,然后就能知道第 \(i\) 个数是 \(0\) 还是 \(1\) 了,然后再还原回去。当然有一个问题就是除开 \(a_i\) 以外剩下的 \(01\) 数量相等,这里我们可以把 \([i,i]\) 改为 \([i,i+1]\),这样每次能得到 \(a_i + a_{i+1}\),最后再统计一下就可以了。这样我们就得到了一个期望 \(8n\) 次询问的做法。
Code:
#include <bits/stdc++.h>
using namespace std;
#define ff fflush(stdout)
const int N = 305;
int n, k;
int ans[N], a[N];
int ask(int l, int r) {
printf("? %d %d\n", l, r);
ff;
int res; scanf("%d", &res);
return res;
}
void print() {
printf("! ");
for (int i = 1; i <= n; ++i) printf("%d", ans[i]);
}
int work(int l, int r) {
int res;
do { res = ask(l, r), res = ask(l, r); } while (res == k);
int dis = res - (n - k);
do { res = ask(l, r), res = ask(l, r); } while (res != k);
return (r - l + 1 + dis) / 2;
}
int main() {
scanf("%d%d", &n, &k);
if (n == 2 * k + 1 || n == 2 * k - 1) {
for (int i = 1; i < n; ++i) a[i] = work(i, i + 1);
a[n] = 2 * k;
for (int i = 1; i < n; ++i) a[n] -= a[i];
for (int i = 1; i < n; ++i) {
if (i & 1) ans[n] -= a[i];
else ans[n] += a[i];
}
ans[n] = (ans[n] + a[n]) / 2;
for (int i = n - 1; i; --i) ans[i] = a[i] - ans[i + 1];
}
else for (int i = 1; i <= n; ++i) ans[i] = work(i, i);
print();
return 0;
}