こういうの楽しいよね!
問題へのリンク
問題概要
個のマスが横一列に並んでいます。各マスは赤、青、黄、緑のいずれか 1 色で塗られている ("RBYG" からなる長さ の文字列 で与えられる)。
以下の操作を好きな順序で好きな回数だけ行えます。文字列 を作ることが可能かどうかを判定せよ。
- 異なる色で塗られた隣接 2 マスを選ぶ
- その 2 マスをどちらにも用いられていない 2 色で 1 つずつ塗る
制約
考えたこと
この手の問題は不変量を導きたくなるところ。とりあえず各色を 0, 1, 2, 3 に対応させて考えることにしよう。一瞬、mod とかを考えたくなるけど、それだとあまりうまくいかない。たとえば mod 4 で不変なのかと思いたくなるけど、
- (0, 1) と (2, 3)
- (0, 2) と (1, 3)
- (0, 3) と (1, 2)
のうち、真ん中のやつは mod 4 だと上手くいかない。
XOR
そこで、
- 0 ^ 1 ^ 2 ^ 3 = 0
であることに着目しよう。そうすると、
- 0 ^ 1 = 2 ^ 3
- 0 ^ 2 = 1 ^ 3
- 0 ^ 3 = 1 ^ 2
であることがいえる!!!!!つまり、全体の XOR 和は不変なのだ。S と T とで XOR 和が等しいことが必要条件となる。しかしこれだけでは不十分で、
- S != T
- S がすべて同色
- T がすべて同色
という場合はどうしようもない ( はケースにない)。逆にそうでなければできる。一応そのことを証明してみる。
数学的帰納法
この手の証明は数学的帰納法というイメージがある。まず、 のとき、XOR が等しい全パターン作れることはいえる。とくに、
(0, 1) → (2, 3) → (1, 0)
というように、媒介することで swap ができることに注意しておく。 の場合も大丈夫そう。
それでは、 で がともに全部同色ではないとき、互いに移れることを数学的帰納法によって示そう。まず前提として今回の操作は逆操作が可能なので、あらかじめ や に都合よく操作してしまってかまわない。全部同色でない文字列は、どの隣接する 2 文字も異なるようにできることに注意します。よって次のようにして を一致させることができます。
- S や T をあらかじめ、どの隣接する 2 文字も異なるような状態にしておきます
- S の先頭の 2 文字に対して操作を行うことで、S[0] == T[0] となるようにします
- このとき、S, T の後半 N-1 文字中は「全部同色」という状態ではないので、帰納法の仮定から、互いに一致させることができます
まとめ
- S == T なら Yes
- S または T が「全部同色」なら No
- S の XOR 和 != T の XOR 和なら No
- それ以外は Yes
計算量は 。
#include <bits/stdc++.h> using namespace std; int conv(char c) { if (c == 'R') return 0; else if (c == 'B') return 1; else if (c == 'Y') return 2; else return 3; } bool solve(string S, string T) { if (S == T) return true; int sx = 0, sy = 0; set<int> ss, st; for (auto c : S) ss.insert(c), sx ^= conv(c); for (auto c : T) st.insert(c), sy ^= conv(c); if (ss.size() == 1 || st.size() == 1) return false; return sx == sy; } int main() { int N; string S, T; cin >> N >> S >> T; if (solve(S, T)) cout << "Yes" << endl; else cout << "No" << endl; }