ABC171のE問題に挑戦してみた

初めに

レート400(茶色レート)を超えるためにになるためにAtCoder Problemsを
利用して茶色レート帯の問題を解いていまして、
今までは参加した時にしかブログを書いていなかったのですが、
書いてもまとめた方がお勉強になるので参加していない時も
たまに書こうかと思います。(今週はABCありませんし)

https://kenkoooo.com/atcoder/#/table/

制限時間を決めて解いているんですが、時間内に解き終わらなかったので、
主に解説を見て「なるほどなぁ」となったところについて書いて行きます。

https://atcoder.jp/contests/abc171

※ブログ内で問題の制約事項をすべて記載はしないので、制約事項は↑のURLより参照願います。

E - Red Scarf

N匹の猫がおり、それぞれの猫は整数が記載された赤いスカーフを付けています。
A_1~A_Nまでの入力が与えられ、A_iはi番目の猫のスカーフに記載されている整数を除いた
猫のスカーフに記載された整数をXORした結果となります。
この情報を元にそれぞれの猫のスカーフに記載されている整数を求めます。

解説を見てからの回答
#include<bits/stdc++.h>

using namespace std;
using ll = long long;
const long long INF = 1LL<<60;

typedef pair<ll,ll> Pair;
int main(){

ll N;
ll sum = 0;

cin >> N;

vector<ll> a(N);

// 入力とA1~ANの値のXORした結果を格納
for(ll i = 0;i < N;++i){
    cin >> a[i];
    sum ^= a[i];
}

// 元の値を求る
for(ll i = 0;i < N;++i) a[i] ^= sum;

// 結果を出力
for(ll i = 0;i < N;++i) cout << a[i] << endl;

return 0;

}

※下記に表示しているイメージは0起算で書いてます。

まずは、テストケースのパターンを元に考えてみましょう。
X_iをi番目の猫のスカーフに記載されている整数とすると、
A_1 ~ A_Nを以下のような形で表す事が出来ます。

f:id:hgm_blog:20200906210744p:plain
イメージ

XORの性質について考えて見ると以下のように同じ整数を偶数回XORをすると0となり
奇数回XORをすると1つ分の整数の値となります。

f:id:hgm_blog:20200906215110p:plain
イメージ

この性質を利用して、A_1~A_Nの値を下記例のようにXORすると
XORする前の値(X_1~X_N)をXORした値となります。

f:id:hgm_blog:20200906221404p:plain
イメージ

上記のことが分かったので、A_1~A_Nの値をXORしたものと、
個別にA_iをXORするとX_iの値を元の数が求められます。

f:id:hgm_blog:20200906224253p:plain
イメージ

これをA_1~A_Nのすべてに行うと元の数をすべて求める事が出来ます。

最後に

XOR自体は知っていたんですが、この発想は浮かびませんでしたね。
過去問やると今まで思いつかなかった発想に出くわすのでタメになりますね
継続して過去問を解いていき本番で活かせるようにしていきます!