「解题报告」ARC124F Chance Meeting

发布时间 2023-03-27 21:33:52作者: APJifengc

?这你评 3246?好弱智。

首先容易发现,两个人的路径只会相交在一条直线上,那么若干个交点就都在这一条直线上。

考虑容斥求这个问题,拿至少出现 \(1\) 个交点的方案数减去至少出现 \(2\) 个交点的方案数就是答案。

如何统计至少出现 \(1\) 个交点的方案数?一条直线上的若干交点能够让我们联想到一套链,那么我们可以拿交点数减去相邻两个交点对数,就是有多少种方案数。

首先考虑交点数。考虑枚举交点 \((x, y)\),那么有:

\[\begin{aligned} &\sum_{x=0}^w \sum_{y=0}^h \binom{2x + h}{x, x, y, h - y} \binom{2(w - x) + h}{w - x, w - x, y, h - y}\\ =&\sum_{x=0}^w \sum_{y=0}^h \binom{2x+h}{x} \binom{x + h}{x} \binom{h}{y}\binom{2(w-x)+h}{w-x} \binom{w - x + h}{w - x} \binom{h}{y}\\ =&\sum_{x=0}^w \binom{2x+h}{x} \binom{x + h}{x}\binom{2(w-x)+h}{w-x} \binom{w - x + h}{w - x} \sum_{y=0}^h \binom{h}{y}^2\\ =&\sum_{x=0}^w \binom{2x+h}{x} \binom{x + h}{x}\binom{2(w-x)+h}{w-x} \binom{w - x + h}{w - x} \binom{2h}{h}\\ =&\binom{2h}{h}\sum_{x=0}^w \binom{2x+h}{x} \binom{x + h}{x}\binom{2(w-x)+h}{w-x} \binom{w - x + h}{w - x} \\ \end{aligned} \]

\(f_i = \binom{2i + h}{i} \binom{i + h}{i}\),那么上式就是一个卷积的形式。我们不妨设 \(g_i = \sum_{j=0}^i f_j f_{i - j}\),那么上式子就是 \(\binom{2h}{h} g_w\)

然后考虑相邻交点对数。这个相当于我们枚举两个点,然后需要保证这两个点中间不会有另外一个交点。发现这其实就是一个卡特兰数,那么答案其实就是 \(\binom{2h}{h} \sum_{i=0}^{w - 1} g_i C_{w - 1 - i}\)

那么至少有 \(1\) 个交点的方案数就统计完了。统计至少有 \(2\) 个交点的方案数也是类似的,我们拿相邻交点对数减去相邻三个交点对数就是答案。

相邻三个交点对数也是同样的,我们选取两个点,要求这中间恰好有一个交点,这个方案数就是卡特兰数卷积一下,也很容易算,懒得写式子了。

然后就做完了,好弱智。

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;
}
Polynomial f, g, c, d;
int main() {
    pre(800000);
    scanf("%d%d", &h, &w);
    h--, w--;
    f.set(w);
    for (int i = 0; i <= w; i++) {
        f[i] = 1ll * C(2 * i + h, h) * C(2 * i, i) % P;
    }
    g = f * f;
    c.set(w);
    c[0] = 1;
    for (int i = 1; i <= w; i++) {
        c[i] = (C(2 * i, i) - C(2 * i, i - 1) + P) % P;
    }
    d = c * c;
    int ans = 0;
    // at least 1: 1 - 2
    ans = g[w];
    for (int i = 0; i <= w - 1; i++) {
        ans = (ans - 2ll * g[i] * c[w - 1 - i] % P + P) % P;
    }
    // at least 2: 2 - 3
    for (int i = 0; i <= w - 1; i++) {
        ans = (ans - 2ll * g[i] * c[w - 1 - i] % P + P) % P;
    }
    for (int i = 0; i <= w - 2; i++) {
        ans = (ans + 4ll * g[i] * d[w - 2 - i] % P + P) % P;
    }
    ans = 1ll * ans * C(2 * h, h) % P;
    printf("%d\n", ans);
    return 0;
}