1511E - Colorings and Dominoes
呜,天天只能靠手速上分的日子什么时候才能结束,我也想靠脑子啊(!
题意: 有一个 n × m n \times m n×m的格子图,分黑白格子,白格子可以被染成蓝色或者红色,一个多米诺骨牌占一个 1 × 2 1 \times2 1×2的位置,他可以覆盖两个连续的水平的红色格子或者两个连续的竖着的蓝色啊格子,对于一种染色方案,贡献是能摆放的最多的多米诺骨牌,求所有染色方案的贡献的和 mod 998244353
思路: 转换成概率期望做,答案是 P × 2 w h i t e P \times 2^{white} P×2white,考虑将整张图的横竖分开考虑,对于每个行或列又分开考虑(
因为行和列的情况不会重复
dp出一行长度为k的白格子能放下骨牌数量的期望是多少
2个格子他的概率就是 1 4 \frac{1}{4} 41(两个红色),三个格子就是 1 4 − 1 8 \frac{1}{4} - \frac{1}{8} 41−81(最近的两个是红色,前面那个是蓝色),四个: 1 4 − 1 8 + 1 16 \frac{1}{4} - \frac{1}{8} + \frac{1}{16} 41−81+161 (当前两个是红色,前面的不是,或者四个都是红色) …
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 3e5 + 10;
string mp[N];
ll qpow(ll x, ll n) {
ll res = 1;
while (n) {
if (n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
ll inv(ll x) {
return qpow(x, mod - 2);
}
ll po[N];
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
for (int i = 0; i < n; ++i) {
cin >> mp[i];
}
ll len = max(n, m) + 3;
ll nwres = 0;
for (int i = 2; i <= len; ++i) {
if (i % 2 == 0) {
nwres = (nwres + inv(qpow(2, i))) % mod;
} else {
nwres = (nwres - inv(qpow(2, i)) + mod) % mod;
}
po[i] = nwres;
}
ll ans = 0;
ll white = 0;
for (int i = 0; i < n; ++i) {
ll cnt = 0;
for (int j = 0; j < m; ++j) {
if (mp[i][j] == '*') {
cnt = 0;
} else {
cnt++;
white++;
}
if (cnt > 0) {
ans = (ans + po[cnt]) % mod;
}
}
}
for (int j = 0; j < m; ++j) {
ll cnt = 0;
for (int i = 0; i < n; ++i) {
if (mp[i][j] == '*') {
cnt = 0;
} else {
cnt++;
}
if (cnt > 0) {
ans = (ans + po[cnt]) % mod;
}
}
}
ans = ans * qpow(2, white) % mod;
cout << ans << endl;
}