1. 程式人生 > 其它 >CF1511E Colorings and Dominoes

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; 
}