面白かった。でも茶色ってことは流石になさそう......(コンテスト中は、全部の XOR 和が 0 かどうかを判定する、という嘘解法が AC になっていたらしい)
問題概要
個の非負整数 が与えられる。これらを円環状に上手に並べることで、
「どの整数も両隣の整数の XOR 和に一致する」
という状態にできるかどうかを判定せよ。
制約
考えたこと
整数 をこの順に並べたとき
- = XOR
- = XOR
となることから、これらの両辺の XOR をとると
XOR = 0
⇔
となることが導かれる。つまり、円環状に数値を並べたとき、3 個置きに同じ値になることが必要ということになる。
よって、 が 3 の倍数でない場合には、 と 3 が互いに素であることから、結局すべての値が等しくなる必要があるということになる。その上、連続する 3 つの値 が = XOR という条件を満たすためには
となる必要があることがわかる (逆にすべて 0 なら明らかに Yes)。以上から が 3 の倍数でない場合には、「すべて 0」であることが必要十分であることがわかった。
が 3 の倍数のとき
が 3 の倍数であれば、 XOR XOR = 0 を満たすような を用いて
と円環状に並べたものが唯一の解となる。そのパターンは以下のものがありうる。
- かつ
- XOR XOR = 0 かつ
このようになっているかどうかは簡単な集計処理で調べられる。
コード
計算量は となる。
#include <bits/stdc++.h> using namespace std; int main() { int N; cin >> N; vector<int> A(N); map<int,int> ma; for (int i = 0; i < N; ++i) cin >> A[i], ++ma[A[i]]; auto solve = [&]() -> bool { if (N % 3 != 0) return (ma[0] == N); vector<int> v; for (auto it : ma) v.push_back(it.first); if (v.size() == 1) return (ma[0] == N); else if (v.size() == 2) return (ma[0] == N/3); else if (v.size() == 3) { if ((v[0] ^ v[1] ^ v[2]) != 0) return false; return (ma[v[0]] == N/3 && ma[v[1]] == N/3 && ma[v[2]] == N/3); } else return false; }; cout << (solve() ? "Yes" : "No") << endl; }