難易度評価

難易度を1〜10段階で評価できます。投票はあとから変更・取り消しできます。

難易度(投票) Lv.5.5 (2票)

投票の分布
  1. Lv.10票
  2. Lv.20票
  3. Lv.30票
  4. Lv.40票
  5. Lv.51票
  6. Lv.61票
  7. Lv.70票
  8. Lv.80票
  9. Lv.90票
  10. Lv.100票

難易度の目安を見る ↗

ログインして難易度を投票

外部サイトへ移動します

リンク先の URL を確認してから開いてください。

別タブで開く

Two Prisoners and 01 Array

作成者 loop0919

難易度(作成者設定) Lv.5

難易度(投票) Lv.5.5 (2票)

解法のヒントになることがあります。
実行時間制限
2 秒
メモリ制限
512 MiB

解説

以下では、列の添字を 00 から数えます。つまり B=(B0,B1,…,B2N−1)B = (B_0, B_1, \ldots, B_{2^N - 1}) とします。

方針

0101 列 CC に対して、 Ci=1C_i = 1 である添字 ii すべての排他的論理和(XOR)を f(C)f(C) と書きます。 11 が 11 つもなければ f(C)=0f(C) = 0 です。

Alice と Bob は「 f(B′)=Xf(B') = X となる B′B' を伝える」と決めておきます。

Alice の操作

BB の pp 番目を反転した列を B′B' とします。 BpB_p が 00 から 11 に変わるときは添字 pp が新たに加わり、 11 から 00 に変わるときは添字 pp が取り除かれます。 XOR では加えることと取り除くことが同じ操作なので、どちらの場合も

f(B′)=f(B)⊕pf(B') = f(B) \oplus p

が成り立ちます。

したがって p=f(B)⊕Xp = f(B) \oplus X と選べば、 f(B′)=f(B)⊕f(B)⊕X=Xf(B') = f(B) \oplus f(B) \oplus X = X となります。 f(B)f(B) と XX はどちらも 00 以上 2N−12^N - 1 以下なので、 pp も 00 以上 2N−12^N - 1 以下であり、必ず列の中の添字になります。

反転するのは 11 か所だけなので、 B′B' と BB のハミング距離は 11 です。

なお f(B)=Xf(B) = X のときは p=0p = 0 です。添字 00 は ff の値に影響しないため、 00 番目を反転しても、何も変えずに B′=BB' = B としても構いません。

Bob の操作

受け取った B′B' から f(B′)f(B') を計算して出力します。上で示したとおり、これは XX に一致します。

列の長さが 2N2^N であることについて

Alice が作れる B′B' は、 BB 自身と 11 か所を反転した列の、合わせて 2N+12^N + 1 通りです。一方で伝えたい XX は 2N2^N 通りあります。添字が 00 から 2N−12^N - 1 までちょうど NN ビットで表せるため、 11 か所の反転で ff の値を任意の値に変えられます。

実装

11 行目の文字列が Alice か Bob かで処理を分けます。問題文の添字は 11 から始まるので、 ii 番目の要素を添字 i−1i - 1 として扱う点に注意してください。

#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";
        }
    }
}

計算量

各テストケースについて、どちらの実行でも O(2N)O(2^N) 時間です。

ユーザー解説

ユーザー解説を書く

ユーザー解説はまだありません。