「解题报告」[ARC114E] Paper Cutting 2
Kaguya 随机点了一道题,结果还挺 educational,写一下。
不过好像挺套路的。
首先第一件事,发现从现有的线段里选一个隔开这个东西太丑了。我们考虑转化一下题意。我们仍然在原矩形上划线,但是划完线后并不割开,而是一直在原矩形上操作。可以发现,这个操作是和原来的操作是等价的,因为我们可以看做是每次选了一条线,如果这个线已经不在当前矩形上了就重新选一个,容易发现这个操作的选中每一条线的概率是和原来相等的。
同时,发现原问题的操作次数等价于这个矩形缩小了多少次,那么根据期望的线性性,我们可以将期望拆为对于每一条线,矩形的边界在某一时刻变为这一条线的概率之和。
那么我们枚举每一条线,然后考虑选中它的概率。设上下左右分别有 \(u, d, l, r\) 条可以选的线,总线段数为 \(s\)。假设我们枚举的是左边的第 \(i\) 条线,那么不难发现每次选中其它线的概率为 \(\dfrac{u+d+r+i-1}{s}\)。那么某一时刻选中这条线的概率就是 \(\displaystyle \sum_{j=0}^{\infty} \left(\dfrac{u+d+r+i-1}{s}\right)^j \frac{1}{s} = \frac{1}{s-(u+d+r+i-1)}\)。直接对这个东西求和即可,复杂度 \(O(n \log n)\) 或 \(O(n)\)。
#include <bits/stdc++.h>
using namespace std;
const int P = 998244353;
int h, w;
int h1, h2, w1, w2;
int l, r, u, d, s;
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;
}
int main() {
scanf("%d%d%d%d%d%d", &h, &w, &h1, &w1, &h2, &w2);
l = min(h1, h2) - 1;
r = h - max(h1, h2);
u = min(w1, w2) - 1;
d = w - max(w1, w2);
s = h + w - 2;
int ans = 1;
for (int i = 1; i <= l; i++) {
ans = (ans + qpow(s - r - u - d - i + 1, P - 2)) % P;
}
for (int i = 1; i <= r; i++) {
ans = (ans + qpow(s - l - u - d - i + 1, P - 2)) % P;
}
for (int i = 1; i <= u; i++) {
ans = (ans + qpow(s - r - l - d - i + 1, P - 2)) % P;
}
for (int i = 1; i <= d; i++) {
ans = (ans + qpow(s - r - u - l - i + 1, P - 2)) % P;
}
printf("%d\n", ans);
return 0;
}