解説
以下では、列の添字を から数えます。つまり とします。
方針
列 に対して、 である添字 すべての排他的論理和(XOR)を と書きます。 が つもなければ です。
Alice と Bob は「 となる を伝える」と決めておきます。
Alice の操作
の 番目を反転した列を とします。 が から に変わるときは添字 が新たに加わり、 から に変わるときは添字 が取り除かれます。 XOR では加えることと取り除くことが同じ操作なので、どちらの場合も
が成り立ちます。
したがって と選べば、 となります。 と はどちらも 以上 以下なので、 も 以上 以下であり、必ず列の中の添字になります。
反転するのは か所だけなので、 と のハミング距離は です。
なお のときは です。添字 は の値に影響しないため、 番目を反転しても、何も変えずに としても構いません。
Bob の操作
受け取った から を計算して出力します。上で示したとおり、これは に一致します。
列の長さが であることについて
Alice が作れる は、 自身と か所を反転した列の、合わせて 通りです。一方で伝えたい は 通りあります。添字が から までちょうど ビットで表せるため、 か所の反転で の値を任意の値に変えられます。
実装
行目の文字列が Alice か Bob かで処理を分けます。問題文の添字は から始まるので、 番目の要素を添字 として扱う点に注意してください。
#include <bits/stdc++.h>
using namespace std;
int main() {
string role;
int T;
cin >> role >> T;
while (T--) {
int n;
cin >> n;
int x = 0;
if (role == "Alice") cin >> x;
vector<int> b(1 << n);
int s = 0;
for (int i = 0; i < (1 << n); i++) {
cin >> b[i];
if (b[i]) s ^= i;
}
if (role == "Alice") {
b[s ^ x] ^= 1;
for (int i = 0; i < (1 << n); i++) cout << b[i] << " \n"[i + 1 == (1 << n)];
} else {
cout << s << "\n";
}
}
}
計算量
各テストケースについて、どちらの実行でも 時間です。
ユーザー解説
ユーザー解説を書くユーザー解説はまだありません。