AT ARC202D King

场上做这题把 \(T\) 当成了数据组数。

发现可以走的步满足每一维都在 \(-1\sim 1\) 之中且不为 \((0, 0)\)

因为走了一个 \((0, 0)\) 其实对当前的位置是没有变化的,这启发对走过的 \((0, 0)\) 进行容斥,这样的好处是可以把走的步独立成 \(2\) 个维度去计数。

具体来说,记 \(f_i, g_i\) 表示横轴 / 竖轴走 \(i\) 步(没有不能走 \((0, 0)\) 的限制)的合法方案数,那么可以表示答案为 \(\sum\limits_{i = 0}^T (-1)^{T - i}\binom{T}{i} f_ig_i\)

因为 \(f, g\) 求解的方法是相同的,所以接下来只考虑求解 \(f\)

简化一下,\(f_i\) 相当于是在 \([1, n]\) 的一行中,每一步可以走 \(-1\sim 1\),不能走出去,走 \(i\) 步从 \(x\) 走到 \(y\) 的方案数。

考虑到此时有两种做法:

  • \(dp_{i, j}\) 表示走了 \(i\) 步,现在在 \(j\) 的方案数,时间复杂度 \(\mathcal{O}(nT)\)

  • 反射容斥,转而考虑 \(\mathcal{O}(\frac{T}{n})\) 个点 \(x'\) 走到 \(y\),且没有不能走出去的限制的方案数 \(f'_i\)

    \(d = |x' - y|\),相当于是要求 \(1\) 的步数比 \(-1\) 的步数多 \(d\),即 \(f'_i = \sum\limits_{j = 0}^{\lfloor(i - d) / 2\rfloor} \binom{i}{j, j + d, i - 2j - d} = i! \sum\limits_{j = 0}^{\lfloor(i - d) / 2\rfloor} \frac{1}{j!(j + d)!(i - 2j - d)!}\)

    接下来考虑求解求和这一部分的值。

    因为 \(j, j + d\) 有差为 \(d\) 的关系,于是考虑当作一个整体,记 \(a_i = \begin{cases}\frac{1}{((j - d) / 2)!((j - d) / 2 + d)!} & j\ge d, (j - d)\bmod 2 = 0\\ 0 & \operatorname{otherwise}\end{cases}\)
    \(i - 2j - d\) 当作一个部分,记 \(b_i = \frac{1}{i!}\)
    那么 \(f‘_i\) 求和部分的值就是 \(a, b\) 卷积后的值。

    这部分复杂度为 \(\mathcal{O}(\frac{T^2\log T}{n})\)

考虑阈值分治,当 \(n\le \sqrt{T \log T}\) 时用第一种方法,否则用第二种做法。

最终复杂度为 \(\mathcal{O}(T\sqrt{T\log T})\)

#include <bits/stdc++.h>
#include <atcoder/all>

using mint = atcoder::modint998244353;

constexpr int N = 3e5;

mint fac[N + 1], ifac[N + 1];

inline mint binom(int n, int m) {
    return fac[n] * ifac[n - m] * ifac[m];
}

std::vector<mint> solve(int n, int x, int y, int T) {
    if (n <= 3000) {
        std::vector<mint> f(n, 0), ans(T + 1);
        f[x - 1] = 1, ans[0] = x == y;
        for (int i = 1; i <= T; i++) {
            std::vector<mint> g = f;
            for (int j = 0; j + 1 < n; j++) g[j] += f[j + 1];
            for (int j = 1; j < n; j++) g[j] += f[j - 1];
            f = g, ans[i] = f[y - 1];
        }
        return ans;
    }

    std::vector<mint> ans(T + 1, 0);

    auto calc = [&](int d, mint val) {
        std::vector<mint> a(T + 1, 0), b(T + 1, 0);
        for (int i = 0; i <= T; i++) a[i] = ifac[i];
        for (int i = 0; i * 2 + d <= T; i++) b[i * 2 + d] = ifac[i] * ifac[i + d];
        std::vector<mint> f = atcoder::convolution(a, b);
        for (int i = 0; i <= T; i++) ans[i] += f[i] * fac[i] * val;
    };

    calc(abs(x - y), 1);
    for (int z = x, mid = n + 1, f = -1; ; mid += n + 1, f = -f) {
        z = mid * 2 - z;
        if (z - y > T) break;
        calc(z - y, f);
    }
    for (int z = x, mid = 0, f = -1; ; mid -= n + 1, f = -f) {
        z = mid * 2 - z;
        if (y - z > T) break;
        calc(y - z, f);
    }

    return ans;
}

int main() {
    fac[0] = 1;
    for (int i = 1; i <= N; i++) fac[i] = fac[i - 1] * i;
    ifac[N] = fac[N].inv();
    for (int i = N; i >= 1; i--) ifac[i - 1] = ifac[i] * i;

    int H, W, T, A, B, C, D;
    scanf("%d%d%d%d%d%d%d", &H, &W, &T, &A, &B, &C, &D);

    std::vector<mint> f = solve(H, A, C, T);
    std::vector<mint> g = solve(W, B, D, T);

    mint ans = 0;
    for (int i = 0; i <= T; i++) {
        mint val = f[i] * g[i] * binom(T, i);
        ans += (T - i) & 1 ? (-val) : val;
    }

    printf("%d\n", ans.val());
    return 0;
}
posted @ 2025-08-11 09:06  rizynvu  阅读(14)  评论(0)    收藏  举报