CF1511E Colorings and Dominoes

考虑计数拆开贡献。
因为在一个方案中一个格子最多只会贡献一次,那么不妨反过来求这个格子贡献了多少次。
然后发现,行列独立,那么我们单独计算红蓝色,即可。
一个偶数块贡献当且仅当前面也是偶数块。
然后显然其他不在同一行/同一列的块就直接随便乱取就行了。

#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; 
} 
原文地址:https://www.cnblogs.com/dixiao/p/15472821.html