考虑计数拆开贡献。
因为在一个方案中一个格子最多只会贡献一次,那么不妨反过来求这个格子贡献了多少次。
然后发现,行列独立,那么我们单独计算红蓝色,即可。
一个偶数块贡献当且仅当前面也是偶数块。
然后显然其他不在同一行/同一列的块就直接随便乱取就行了。
#include<iostream>
#include<cstdio>
#include<vector>
#define N 300005
#define mod 998244353
#define ll long long
int n,m;
char a[N];
int sum = 0;
std::vector<int>v[N];
int f[N];
inline ll pow(ll a,ll b){
ll ans = 1;
while(b){
if(b & 1)ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll ans = 0;
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i){
scanf("%s",a + 1);
for(int j = 1;j <= m;++j)
sum += (a[j] == 'o'),v[i].push_back(a[j] == 'o');
}
f[2] = f[3] = 1;
for(int i = 4;i <= sum;++i)
f[i] = (pow(2,i - 3) + f[i - 2]) % mod;
for(int i = 2;i <= sum;++i)
f[i] = f[i] * pow(2,sum - i) % mod;
int now = 0;//当前段长度
for(int i = 1;i <= n;++i,now = 0)
for(int j = 0;j < m;++j){
now = now * v[i][j] + v[i][j];
ans = (ans + f[now]) % mod;
}
now = 0;
for(int j = 0;j < m;++j,now = 0)
for(int i = 1;i <= n;++i){
now = now * v[i][j] + v[i][j];
ans = (ans + f[now]) % mod;
}
std::cout<<ans<<std::endl;
}