(动态规划)Educational Codeforces Round 107 (Rated for Div. 2) E. Colorings and Dominoes

题目:
https://codeforces.ml/contest/1511/problem/E
You have a large rectangular board which is divided into n×m cells (the board has n rows and m columns). Each cell is either white or black.

You paint each white cell either red or blue. Obviously, the number of different ways to paint them is 2w, where w is the number of white cells.

After painting the white cells of the board, you want to place the maximum number of dominoes on it, according to the following rules:

  • each domino covers two adjacent cells;
  • each cell is covered by at most one domino;
  • if a domino is placed horizontally (it covers two adjacent cells in one of the rows), it should cover only red cells;
  • if a domino is placed vertically (it covers two adjacent cells in one of the columns), it should cover only blue cells.

Let the value of the board be the maximum number of dominoes you can place. Calculate the sum of values of the board over all 2w possible ways to paint it. Since it can be huge, print it modulo 998244353.

Input
The first line contains two integers n and m (1≤n,m≤3⋅105; nm≤3⋅105) — the number of rows and columns, respectively.

Then n lines follow, each line contains a string of m characters. The j-th character in the i-th string is * if the j-th cell in the i-th row is black; otherwise, that character is o.

Output
Print one integer — the sum of values of the board over all 2w possible ways to paint it, taken modulo 998244353.

Input

3 4
**oo
oo*o
**oo

Output

144

Input

3 4
**oo
oo**
**oo

Output

48

Input

2 2
oo
o*

Output

4

Input

1 4
oooo

Output

9

思路:
可以把问题拆分成求每行每列相邻的 ‘o’ 的可以放置的domino的数量的和。
设dp [ i ]是 i个相邻的 ‘o’ 的可以放置的domino的数量,那么,
dp [ i ] = dp [ i - 2] * 2 + dp [ i - 1] + 2 ^ (i - 2)
在这里插入图片描述每个相邻的 'o’的可以放置的domino的数量产生的贡献 = dp [ i ] * 2 ^ ( ‘0’ 的总个数 - i)

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 3e5 + 10;
const ll MOD = 998244353;
string s[MAXN];
ll pow2[MAXN], dp[MAXN];
int main(){
	ios_base::sync_with_stdio(false), cin.tie(0);
	int n, m;
	int cnt = 0;
	cin >> n >> m;
	for (int i = 0; i < n; i++){
		cin >> s[i];
		for (int j = 0; j < m; j++)
			if (s[i][j] == 'o')
				cnt++;
	}
	dp[2] = pow2[0] = 1;
	for (int i = 1; i <= cnt; i++)
		pow2[i] = (pow2[i-1] << 1) % MOD;
	for (int i = 3; i <= cnt; i++)
		dp[i] = (dp[i-1] + (dp[i-2] << 1) + pow2[i-2]) % MOD;
	ll ans = 0, temp;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (s[i][j] == 'o'){
				temp = 1;
				while (++j < m && s[i][j] == 'o')
					temp++;
				if (temp >= 2)
					ans = (ans + dp[temp] * pow2[cnt-temp]) % MOD;
			}
	for (int i = 0; i < m; i++)
		for (int j = 0; j < n; j++)
			if (s[j][i] == 'o'){
				temp = 1;
				while (++j < n && s[j][i] == 'o')
					temp++;
				if (temp >= 2)
					ans = (ans + dp[temp] * pow2[cnt-temp]) % MOD;
			}
	cout << ans;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值