「解题报告」[ARC114E] Paper Cutting 2

发布时间 2023-05-29 21:48:13作者: APJifengc

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;
}