题意:n*m的棋盘,每个格点有三种颜色,红色,蓝色或者白色。现在要把所有白色的点都染成红色或者蓝色,要求染完后对于这个棋盘上任意一个偶数长偶数宽的长方形,里面红色的点的个数都等于蓝色的点的个数,求有几种染色方案。
把红色当做1,蓝色当做0。如果现在最左上角是这样的:
⎡⎣⎢⎢⎢10⋮10⋮⋯⋯⋱⎤⎦⎥⎥⎥
那从第三行开始每行的前两个就已经确定了,就是说第三行的前两个是1,1,第四行的前两个是0,0,…
而第三列的前两行的两个数影响了整个表格:
⎡⎣⎢⎢⎢⎢⎢⎢1010⋮1010⋮1010⋮1010⋮⋯⋯⋯⋯⋱⎤⎦⎥⎥⎥⎥⎥⎥
或者是
⎡⎣⎢⎢⎢⎢⎢⎢1010⋮1010⋮0101⋮1010⋮⋯⋯⋯⋯⋱⎤⎦⎥⎥⎥⎥⎥⎥
也就是说每行都是 01 循环或者 10 循环或者每列都是 01 循环或者 10 循环。
所以可以对每行先假设它第一个是
1
,跑一遍看是否可行,再假设是
然而还有一个问题,在下面这两种情况下,可以同时看做每行的 10 或者 01 循环或者是每列的 10 或者 01 循环。
⎡⎣⎢⎢⎢⎢⎢⎢1010⋮0101⋮1010⋮0101⋮⋯⋯⋯⋯⋱⎤⎦⎥⎥⎥⎥⎥⎥
或者
⎡⎣⎢⎢⎢⎢⎢⎢0101⋮1010⋮0101⋮1010⋮⋯⋯⋯⋯⋱⎤⎦⎥⎥⎥⎥⎥⎥
所以要再特地去跑一遍这两种情况,如果能满足的话就减1。
其实这题不是很难,但是比赛的时候没去看 :(
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
int T;
int n,m;
char a[1050][1050];
int main(){
scanf("%d",&T);
while (T--){
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%s",a[i]+1);
}
ll ans1=1;
for (int i=1;i<=n;i++){
int cnt=0;
bool flag=true;
for (int j=1;j<=m;j++){
if (j%2==0){
if (a[i][j]=='R') flag=false;
}
else{
if (a[i][j]=='B') flag=false;
}
}
if (flag) cnt++;
flag=true;
for (int j=1;j<=m;j++){
if (j%2==0){
if (a[i][j]=='B') flag=false;
}
else{
if (a[i][j]=='R') flag=false;
}
}
if (flag) cnt++;
ans1=ans1*cnt%mod;
}
ll ans2=1;
for (int j=1;j<=m;j++){
int cnt=0;
bool flag=true;
for (int i=1;i<=n;i++){
if (i%2==1){
if (a[i][j]=='R') flag=false;
}
else{
if (a[i][j]=='B') flag=false;
}
}
if (flag) cnt++;
flag=true;
for (int i=1;i<=n;i++){
if (i%2==1){
if (a[i][j]=='B') flag=false;
}
else{
if (a[i][j]=='R') flag=false;
}
}
if (flag) cnt++;
ans2=ans2*cnt%mod;
}
ll ans=(ans1+ans2)%mod;
bool flag=true;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if ((i+j)%2==1){
if (a[i][j]=='R') flag=false;
}
else{
if (a[i][j]=='B') flag=false;
}
}
}
if (flag) ans=(ans-1+mod)%mod;
flag=true;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if ((i+j)%2==1){
if (a[i][j]=='B') flag=false;
}
else{
if (a[i][j]=='R') flag=false;
}
}
}
if (flag) ans=(ans-1+mod)%mod;
printf("%lld\n",ans);
}
}