题目要求不能有有三个连续相同的'X'或'O',注意到这样的连续串它们的横纵坐标之和是连续变化的,考虑将它们按照横纵坐标之和对 (3)的模值分组,因为这样分组后相邻的三个相同字符就被分到了三个不同的组中,这样可以通过将其中一个组的字符所在位置全部变为其他字符,这样就保证没有三个连续相同字符了,那么我们分别从'X'和'O'中选出一组转化为其他字符就可以保证满足没有三个连续相同字符了。但是考虑这样的情况: (egin{matrix}.X. \ OOO \ .X.end{matrix}),假定中间那个'O'的横纵坐标和对 (3)的模值是 (2),这时如果'O'选的组和'X'选的组都都是模值为 (2)的,那么最终就会变成这样:(egin{matrix}.X. \ OXO \ .X.end{matrix}),明显不满足,原因在于虽然没有连续三个'O'了,但却造成了连续三个'X',而且由于这是后天造成的,之前的分组对这个新形成的'X'不起作用,导致前面的做法假了。为了避免这种情况,我们只需从'X'和 'O'中选出模数不同的两组即可。证明:假定从'X'中选出了横纵坐标和模 (3)为 (1)的组,从'O'中选出了模为 (2)的组,这样新产生的'X'或'O'都不会再形成新的 (3)连续相同字符序列。举个例子,坐标为 ((2,2))的'X'变成了'O',它的坐标和对 (3)取模是 (1),也就是从 'X'选的组的模值是 (1),那么从'O'中选的组的模值要么是 (0)要么是 (2),而一个 (3)连续序列必然同时包含模值为 (0,1,2)的点,现在缺失了 (0)或 (2)故不可能产生新的连续序列。证毕。然后为了满足题目操作限制的要求,我们需要选择两个组满足这两个组包含的点数最少。
#include<cstdio>
#include<cstring>
int T, n;
int X[5], O[5];
char s[305][305];
int main(){
scanf("%d", &T);
while(T--){
scanf("%d", &n);
memset(X, 0, sizeof(X));
memset(O, 0, sizeof(O));
for(int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
for(int i = 1; i <= n; ++i)
for(int t = 1; t <= n; ++t){
if(s[i][t] == 'X') ++X[(i + t) % 3];
if(s[i][t] == 'O') ++O[(i + t) % 3];
}
int minn = 1e9, j, k;
for(int i = 0; i < 3; ++i)
for(int t = 0; t < 3; ++t)
if(i != t && X[i] + O[t] < minn){
minn = X[i] + O[t];
j = i, k = t;
}
for(int i = 1; i <= n; ++i)
for(int t = 1; t <= n; ++t){
if(s[i][t] == 'X' && (i + t) % 3 == j) s[i][t] = 'O';
if(s[i][t] == 'O' && (i + t) % 3 == k) s[i][t] = 'X';
}
for(int i = 1; i <= n; ++i) puts(s[i] + 1);
}
return 0;
}