これ好き!
問題概要
のグリッドがあって、"." と "O" と "X" のいずれかが描かれている。"O" または "X" の描かれているマス目の個数を とする。
今、いくつかのマスに対して、"O" または "X" のマス目の "OX" を入れ替える操作を行う。それによって「どの連続する 3 マス (縦横のみ, 斜めは除く) も "O" または "X" が連続していない」という状態にしたい。
ただし、操作を行うマスの個数は (切り下げ) 以下でなければならない。そのような操作を実施した結果を一つ示せ。
制約
- テストケース数
考えたこと
たとえば次のように、マス に対して
- がある値のところはすべて "O"
- が他のある値のところはすべて "X"
という状態にできたならば、他のマスがどうあろうと条件を満たす。
o . x o . x o . x o . x o . x o . x o . x o . x o . x o . x o . x o . x o . x o . x o . x o . x o
の値が 0, 1, 2 であって、"O", "X" であるものの個数を とする。このとき、鳩の巣原理より、
を満たすように を選ぶことができる。さらに、 を適宜入れ替えることによって、
を満たすようにできる。よって、
- であるような を "X" に
- であるような を "O" に
すれば OK。
コード
実装上は、6 通りの割当パターンを順に試して、変更箇所が 以下になるものを探索した。
#include <bits/stdc++.h> using namespace std; #define REP(i,n) for(long long i = 0; i < (long long)(n); ++i) int main() { int TTT; cin >> TTT; while (TTT--) { int N; cin >> N; vector<string> fi(N); for (int i = 0; i < N; ++i) cin >> fi[i]; int num = 0; REP(i, N) REP(j, N) if (fi[i][j] != '.') ++num; auto solve = [&]() -> void { for (int maru = 0; maru < 3; ++maru) { for (int batu = 0; batu < 3; ++batu) { if (maru == batu) continue; int num2 = 0; REP(i, N) REP(j, N) { if ((i+j) % 3 == maru && fi[i][j] == 'X') ++num2; if ((i+j) % 3 == batu && fi[i][j] == 'O') ++num2; } if (num2 <= num / 3) { REP(i, N) REP(j, N) { if ((i+j) % 3 == maru && fi[i][j] == 'X') fi[i][j] = 'O'; if ((i+j) % 3 == batu && fi[i][j] == 'O') fi[i][j] = 'X'; } for (auto str : fi) cout << str << endl; return; } } } }; solve(); } }