题目
思路
我吐了,这道题做了 1 h 1h 1h 也做不出来。真的很 t r i c k y \rm tricky tricky 啊……
考虑这样一个事实:任意一个横着或竖着的连续三格,都涉及到了 三条对角线(左下到右上)。对角线的编号是
x
+
y
x+y
x+y,将它们按照模三的余数分类。如果在某一个类中,根本没有 X
出现过,那么就不会形成 X
的胜利局面,O
也是同理。
于是问题转化为,给 X
和 O
分别选择一个不能出现类
a
,
b
(
a
≠
b
)
a,b\;(a\ne b)
a,b(a=b),操作次数就是
c
n
t
a
(
X
)
+
c
n
t
b
(
O
)
cnt_{a}(X)+cnt_b(O)
cnta(X)+cntb(O) 。只需要它不超过
⌊
k
3
⌋
\lfloor{k\over 3}\rfloor
⌊3k⌋ 。
这样的 a , b a,b a,b 一定存在。若 a , b a,b a,b 可以同时取到最小值(让 c n t a ( X ) cnt_a(X) cnta(X) 最小)就已经成立了,因为二者都不超过总数的 1 3 1\over 3 31 。否则,考虑这三个组合: c n t ( X ) cnt(X) cnt(X) 的最小与 c n t ( O ) cnt(O) cnt(O) 的次小; c n t ( X ) cnt(X) cnt(X) 的次小与 c n t ( O ) cnt(O) cnt(O) 的最小; c n t ( X ) cnt(X) cnt(X) 的最大与 c n t ( O ) cnt(O) cnt(O) 的最大。前两个组合都合法,而且都严格小于第三个组合。这三个组合的和显然是 k k k,如果前两个都大于 ⌊ k 3 ⌋ \lfloor{k\over 3}\rfloor ⌊3k⌋,那么第三个也大于 ⌊ k 3 ⌋ \lfloor{k\over 3}\rfloor ⌊3k⌋,矛盾。
但是这样实现挺麻烦,不如直接枚举 a , b a,b a,b 找最小的一个。反正有解嘛。复杂度 O ( n 2 ) \mathcal O(n^2) O(n2) 。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long int_;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
inline int ABS(const int &x){
return x < 0 ? -x : x;
}
const int MaxN = 305;
char maze[MaxN][MaxN];
int cnt[300][3];
int main(){
for(int T=readint(); T; --T){
int n = readint();
rep(j,0,2) // clear
cnt['X'][j] = cnt['O'][j] = 0;
rep(i,1,n){
scanf("%s",maze[i]+1);
rep(j,1,n) ++ cnt[
int(maze[i][j])][(i+j)%3];
}
int a = 0, b = 0, mn = n*n;
rep(i,0,2) rep(j,0,2)
if(i != j && cnt['X'][i]+cnt['O'][j] < mn){
mn = cnt['X'][i]+cnt['O'][j];
a = i, b = j;
}
rep(i,1,n){
rep(j,1,n)
if(maze[i][j] == 'X')
if((i+j)%3 == a)
putchar('O');
else putchar('X');
else if(maze[i][j] == 'O')
if((i+j)%3 == b)
putchar('X');
else putchar('O');
else putchar('.');
putchar('\n');
}
}
return 0;
}