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;
}
posted @ 2022-10-02 21:58  Kobe303  阅读(26)  评论(0编辑  收藏  举报