DataBase

  • 你的目标是将一个 8-bit 的数 \(X\) 置零
  • 你每次可以选择一个数 \(W\),令 \(X \leftarrow X \oplus W\), \(\oplus\) 是按位异或。
  • 然而有一个坏入,每次会将你的 \(W\) 随机循环位移。
  • 同时你无法得知 \(X\) 具体的值,只知道 \(X\) 的 popcount。
  • \(300\) 次尝试内将这个数置零。

非常厉害的做法。

考虑找到一个操作的序列 \(p\),使得我们依次操作 \(W=p_i\) 之后 \(X\) 至少被置零一次。

先考虑 1-bit 的情况。

此时只需要 \(p_1=[1]\) 即可解决。

接下来我们考虑 2-bit。

如果 \(X=11\),那么我们操作 \(W=11\),此时 \(X\) 被置零。

假如 \(X=01/10\),那么第一次操作之后 \(X\) 仍然是 \(01/10\)

那么我们操作 \(W=10\),要么 \(X\) 被置零,要么 \(X=11\),再次操作 \(W=11\) 即可。

所以 2-bit 对应的操作序列就是 \(p_2=[11,10,11]\)

我们继续考虑 \(2^t\)-bit 的情况对应的操作序列 \(p_t\)

首先我们发现,对于前 \(k\) 位与后 \(k\) 位相同的数 \(Y\),对 \(Y\) 进行 \(2k\)-循环位移 本质上相当于对 \(Y\) 的前 \(k\) 位和后 \(k\) 位分别进行 \(k\)-循环位移。

例如说,假设 \(\overline{x_0x_1x_2x_3}\)\(\overline{y_0y_1y_2y_3}\) 是两个相同的 4-bit 数。

我们对 \(\overline{x_0x_1x_2x_3y_0y_1y_2y_3}\) 进行循环位移。

假设得到的是 \(\overline{y_1y_2y_3x_0x_1x_2x_3y_0}\),这个时候两边分别是 \(\overline{y_1y_2y_3x_0}\)\(\overline{x_1x_2x_3y_0}\)

由于 \(x_i=y_i\),所以两边相当于 \(\overline{x_1x_2x_3x_0}\)\(\overline{y_1y_2y_3y_0}\),也就是分别循环位移了。

那么,如果当前的数 \(X\) 的前一半与后一半相同,那么我们将 \(p_{t-1}\) 中的每个数都复制一份放在后一半,然后进行操作。

也就是类似于这样:\([1111,1010,1111]\)

这其实相当于对前一半和后一半分别操作一遍 \(p_{t-1}\),这必然能还原整个 \(X\)

但是如果前两位和后两位不相同怎么办呢?

这里有一个结论,选取操作序列,将前一半的位设为 \({p_{t-1}}_i\),后一半的位归零。

也就是类似于:\([1100,1000,1100]\)

对这个操作序列操作完后,前一半和后一半必定相同。

这是为什么呢?

我们令 \(x_0\) 表示 \(X\) 的前一半,\(x_1\) 表示 \(X\) 的后一半。

考虑 \(x_0 \oplus x_1\) 的结果。

首先,一个类似于 \(\overline{x_0x_1x_2x_30000}\) 的位移之后。

可能类似于这样:\(\overline{000x_0x_1x_2x_30}\)

此时我们对 \(X\) 异或上他之后,\(x_0\) 异或上了\(\overline{000x_0}\)\(x_1\) 异或上了\(\overline{x_1x_2x_30}\)

那么 \(x_0\oplus x_1\) 就被异或上了 \(\overline{x_1x_2x_3x_0}\),也就是 \(\overline{x_0x_1x_2x_3}\) 的循环位移。

又因为我们知道 \(p_{t-1}\) 能够置零一个序列,那么中间必有一个时刻 \(x_0\oplus x_1=0\),也就是 \(x_0=x_1\),那么此时两半就相等了。

所以递归构造即可。


代码出乎意料的短啊()

#include <iostream>
#include <bitset>

typedef std::basic_string<int> array;

array generate(int layer) {
	if(layer == 0) return {1};
	array f = generate(layer - 1), res;
	int w = 1 << (layer - 1);
	for(auto& x: f) x |= x << w;
	for(auto& x: f) res += f, res += x & ((1 << w) - 1);
	return res + f;
}

inline void solve(array& solution) {
	for(auto& x: solution) {
		std::cout << std::bitset<8>(x) << std::endl;
		int n; std::cin >> n; if(!n) return ;
	}
}

int main() {
	array solution = generate(3);
	int t; std::cin >> t; for(; t--; ) solve(solution);
}
posted @ 2025-09-06 21:41  CuteNess  阅读(8)  评论(0)    收藏  举报