「解题报告」ARC132E Paw

好简单的题,但是我没想到咋做,我一上来就想把贡献拆开,然后推出了一个根本无法化简的式子,哈哈。

仔细考虑一下,发现最后的形式一定是有一段没有被覆盖过,其它的都覆盖过,即形如 <<<<<<<=======>>>>>>>>

那么可以枚举不变的一段,然后计算让这一段不变的概率。考虑左右是独立的,可以先计算两边的方案数,然后组合数合起来,最后一块算概率。

考虑左边。我们每次删一个点,要不然就是删最右边的点,此时这个点必须向左;要不然就是删左边的点,此时方向任意。那么实际上方案数就是 \(1 \times 3 \times 5 \times \cdots \times (2k-1)\)。预处理一下即可。

然后做完了,非常简单。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005, P = 998244353;
int n;
char s[MAXN];
int fac[MAXN], inv[MAXN];
int qpow(int a, int b) {
    int ans = 1;
    while (b) {
        if (b & 1) ans = 1ll * ans * a % P;
        a = 1ll * a * a % P;
        b >>= 1;
    }
    return ans;
}
void pre(int n) {
    fac[0] = 1;
    for (int i = 1; i <= n; i++) {
        fac[i] = 1ll * fac[i - 1] * i % P;
    }
    inv[n] = qpow(fac[n], P - 2);
    for (int i = n; i >= 1; i--) {
        inv[i - 1] = 1ll * inv[i] * i % P;
    }
}
int C(int n, int m) {
    if (n < 0 || m < 0 || n < m) return 0;
    return 1ll * fac[n] * inv[m] % P * inv[n - m] % P;
}
int f[MAXN];
int main() {
    scanf("%d%s", &n, s + 1);
    pre(2 * n);
    vector<int> pos = { 0 };
    for (int i = 1; i <= n; i++) {
        if (s[i] == '.') {
            pos.push_back(i);
        }
    }
    pos.push_back(n + 1);
    int m = pos.size() - 2;
    int tot = 1, ans = 0;
    for (int i = 2; i <= 2 * m; i += 2) {
        tot = 1ll * i * tot % P;
    }
    f[0] = 1;
    for (int i = 1; i <= n; i++) {
        f[i] = 1ll * f[i - 1] * (2 * i - 1) % P;
    }
    for (int i = 0; i < pos.size() - 1; i++) {
        int l = pos[i] + 1, r = pos[i + 1] - 1;
        int cnt = l - 1;
        for (int j = l; j <= r; j++) {
            if (s[j] == '<') cnt++;
        }
        ans = (ans + 1ll * C(m, i) * f[i] % P * f[m - i] % P * cnt) % P;
    }
    ans = 1ll * ans * qpow(tot, P - 2) % P;
    printf("%d\n", ans);
    return 0;
}
posted @ 2023-03-15 20:13  APJifengc  阅读(36)  评论(1编辑  收藏  举报