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);
}
本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/19077398

浙公网安备 33010602011771号