http://acm.hdu.edu.cn/showproblem.php?pid=6122
有一个n行m列的棋盘,最初每个位置是指定的红色或蓝色或白色。你要将白色的位置染成红色或蓝色,使得对于任意一个长宽均为偶数的连续子棋盘,其中红色和蓝色的位置数相等,求方案数模998244353。1≤n,m≤103。
即每个2*2连续子矩阵红蓝数量相等。令红为1,蓝为0,如果让把所有格子按行号与列号的和奇偶反色,则转化为每个2*2子矩阵对角线的和相等。发现这个条件当且仅当每行都是全1或全0,或者每列都是全1或全0,讨论一下就好了。
(自http://bestcoder.hdu.edu.cn/blog/
需要特殊注意下每行全涂黑和每列全涂黑是一样的,白也是
#include<bits/stdc++.h>
using namespace std;
const int mo=998244353;
char ch[1005][1005];
int a1[1005],b1[1005];
char a2[1005],b2[1005];
int main()
{
int T,i,j,n,m;
cin>>T;
while(T--)
{
cin>>n>>m;
for(i=1;i<=n;i++)
scanf("%s",ch[i]+1);
for(i=1;i<=n;i++)
a1[i]=2,a2[i]='?';
for(i=1;i<=m;i++)
b1[i]=2,b2[i]='?';
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if((i+j)&1)
{
if(ch[i][j]=='R')
ch[i][j]='B';
else if(ch[i][j]=='B')
ch[i][j]='R';
}
if(ch[i][j]=='R')
{
if(a1[i])
{
if(a2[i]=='?')
a2[i]='R',a1[i]=1;
else if(a2[i]=='B')
a1[i]=0;
}
if(b1[j])
{
if(b2[j]=='?')
b2[j]='R',b1[j]=1;
else if(b2[j]=='B')
b1[j]=0;
}
}
else if(ch[i][j]=='B')
{
if(a1[i])
{
if(a2[i]=='?')
a2[i]='B',a1[i]=1;
else if(a2[i]=='R')
a1[i]=0;
}
if(b1[j])
{
if(b2[j]=='?')
b2[j]='B',b1[j]=1;
else if(b2[j]=='R')
b1[j]=0;
}
}
}
}
long long ans2=1,ans1=1;
int flog1=0,flog2=0,flog=1,flogg=1;
for(i=1;i<=n;i++)
{
if(a1[i]==1&&a2[i]=='B'||a1[i]==0)
flog=0;
if(a1[i]==1&&a2[i]=='R'||a1[i]==0)
flogg=0;
}
if(flog)flog1++;if(flogg)flog2++;
flog=1,flogg=1;
for(i=1;i<=m;i++)
{
if(b1[i]==1&&b2[i]=='B'||b1[i]==0)
flog=0;
if(b1[i]==1&&b2[i]=='R'||b1[i]==0)
flogg=0;
}
if(flog)flog1++;if(flogg)flog2++;
for(i=1;i<=n;i++)
{
ans1=(ans1*a1[i])%mo;
}
for(i=1;i<=m;i++)
{
ans2=(ans2*b1[i])%mo;
}
// cout<<flog1<<" "<<flog2<<endl;
cout<<(ans1+ans2+(flog1==2?-1:0)+(flog2==2?-1:0)+mo)%mo<<endl;
}
return 0;
}