AGC060C Large Heap 题解

Description

考虑 (1,2,...,2N1)(1,2,...,2^N-1) 的一个排列 P=(P1,P2,...,P2N1)P=(P_1,P_2,...,P_{2^N-1})。称 PP 像堆当且仅当 Pi<P2iP_i \lt P_{2i}Pi<P2i+1P_i \lt P_{2i+1}1i2N111 \le i \le 2^{N-1}-1 成立。

给定正整数 AABB。令 U=2AU=2^AV=2B+11V=2^{B+1}-1。在所有像堆的排列中任取一个,求 PU<PVP_U \lt P_V 的概率。模 998244353998244353

Solution

容易发现 UUVV 分别是小根堆里面第 AA 行最左边的一个和第 BB 行最右边的一个,因此 UU 相当于从根一直往左跳的结果,VV 相当于从根一直往右跳的结果。

又因为求的是概率,所以我们就只需要关心从根往左和往右跳的路径上的数的大小关系。

考虑从小到大往两条路径上加数,然后 dp。

fi,j,0/1f_{i,j,0/1} 表示当前左边加到了第 ii 行,右边加到了第 jj 行,且最后一次是加到了左边/右边的概率,初始值是 f0,0,0=1f_{0,0,0}=1

由于左右边的概率不定,所以要求出往左边加和往右边的概率。

i+1i+1 为根的子树大小为 xxj+1j+1 为根的子树大小为 yy。那么这 x+yx+y 个数的最小值是 i+1i+1 的概率就是 (x+y1x1)(x+yx)=xx+y\displaystyle\frac{\binom{x+y-1}{x-1}}{\binom{x+y}{x}}=\frac{x}{x+y},所以下一步加到左边的概率就是 xx+y\displaystyle\frac{x}{x+y},加到右边的概率就是 yx+y\displaystyle\frac{y}{x+y}

所以:

fi+1,j,0(fi,j,0+fi,j,1)xx+yfi,j+1,1(fi,j,0+fi,j,1)yx+yf_{i+1,j,0}\leftarrow\left(f_{i,j,0}+f_{i,j,1}\right)\cdot \frac{x}{x+y}\\ f_{i,j+1,1}\leftarrow\left(f_{i,j,0}+f_{i,j,1}\right)\cdot \frac{y}{x+y}

ii 行对应点的子树大小很好求,就是 2ni12^{n-i}-1


最后就是最终答案。

考虑枚举左边第一次到达 AA 时右边的位置,假设为 kk,那么到达这个状态后,之后怎么加都会满足 PU<PVP_U<P_V,所以贡献就是 fA,i,0f_{A,i,0}

所以结果为:i=1B1fA,i,0\displaystyle\sum_{i=1}^{B-1}{f_{A,i,0}}

时间复杂度:O(n2logMOD)O(n^2\log \text{MOD})

(那个 logMOD\log\text{MOD} 是在转移过程中求逆元的 log\log

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <bits/stdc++.h>

// #define int int64_t

using i64 = int64_t;

const int kMaxN = 5005, kMod = 998244353;

int n, A, B;
int f[kMaxN][kMaxN][2], s[kMaxN];

int qpow(int bs, int idx = kMod - 2) {
int ret = 1;
for (; idx; idx >>= 1, bs = (i64)bs * bs % kMod)
if (idx & 1)
ret = (i64)ret * bs % kMod;
return ret;
}

void dickdreamer() {
std::cin >> n >> A >> B;
s[n - 1] = 1;
for (int i = n - 2; ~i; --i)
s[i] = (2ll * s[i + 1] + 1) % kMod;
f[0][0][0] = 1;
for (int i = 0; i <= A; ++i) {
for (int j = 0; j <= B; ++j) {
int p = (i64)s[i + 1] * qpow((s[i + 1] + s[j + 1]) % kMod) % kMod;
f[i + 1][j][0] = (f[i + 1][j][0] + (i64)p * (f[i][j][0] + f[i][j][1]) % kMod) % kMod;
f[i][j + 1][1] = (f[i][j + 1][1] + (i64)(kMod + 1 - p) % kMod * (f[i][j][0] + f[i][j][1]) % kMod) % kMod;
}
}
int ans = 0;
for (int i = 0; i < B; ++i)
ans = (ans + f[A][i][0]) % kMod;
std::cout << ans << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

AGC060C Large Heap 题解
https://sobaliuziao.github.io/2023/08/25/post/fb09da6c.html
作者
Egg_laying_master
发布于
2023年8月25日
许可协议