好简单的题,但是我没想到咋做,我一上来就想把贡献拆开,然后推出了一个根本无法化简的式子,哈哈。
仔细考虑一下,发现最后的形式一定是有一段没有被覆盖过,其它的都覆盖过,即形如 <<<<<<<=======>>>>>>>>
。
那么可以枚举不变的一段,然后计算让这一段不变的概率。考虑左右是独立的,可以先计算两边的方案数,然后组合数合起来,最后一块算概率。
考虑左边。我们每次删一个点,要不然就是删最右边的点,此时这个点必须向左;要不然就是删左边的点,此时方向任意。那么实际上方案数就是 \(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;
}
标签:ARC132E,Paw,int,inv,times,1ll,解题,MAXN,ans
From: https://www.cnblogs.com/apjifengc/p/17219838.html