cf1511E - Colorings and Dominoes

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} 4181(最近的两个是红色,前面那个是蓝色),四个: 1 4 − 1 8 + 1 16 \frac{1}{4} - \frac{1}{8} + \frac{1}{16} 4181+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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值