1 条题解

  • 0
    @ 2025-10-22 16:07:10

    题目理解

    我们在三维空间 (x,y,z)(x,y,z) 中,从 (0,0,0)(0,0,0) 走到 (n,m,r)(n,m,r),移动规则是:

    • xxx \to x' 当且仅当 xxx \subseteq x'(即 x & x=xx \ \&\ x' = x,二进制包含关系)
    • 同理 yyy \to y'zzz \to z'

    有些点是障碍,求合法路径数,对 998244353998244353 取模。


    关键观察

    1. 二进制包含关系的组合意义

    如果 xxx \subseteq x',那么在二进制下,xx'11 的位置包含了 xx 的所有 11 的位置。

    xxxx' 的路径数,相当于在 xx'xx 多出的那些 11 位中,按任意顺序依次添加这些 11

    popcount(x)=\text{popcount}(x) = xx 的二进制中 11 的个数,
    00xx 的路径数 ==popcount(x)\text{popcount}(x)11 按任意顺序添加的方案数
    == popcount(x)!\text{popcount}(x)! 种(在 xx 坐标上)。


    2. 三维独立性与组合数

    因为三个坐标的移动是独立的,所以从 (0,0,0)(0,0,0)(x,y,z)(x,y,z) 的路径数
    == $f(\text{popcount}(x), \text{popcount}(y), \text{popcount}(z))$
    == 三个坐标各自添加 11 的顺序方案数的乘积,但要考虑不同坐标间的交错顺序。


    算法解析

    1. 预处理组合数和 ff 数组

    for (int i = 0; i < 64; i++) {
        co[i][0] = 1;
        for (int j = 1; j <= i; j++) {
            co[i][j] = (co[i - 1][j] + co[i - 1][j - 1]) % mod;
        }
    }
    

    这里 co[i][j]\text{co}[i][j] 是组合数 CijC_i^j


    f[0][0][0] = 1;
    for (int i = 0; i < 64; i++) {
        for (int j = 0; j < 64; j++) {
            for (int k = 0; k < 64; k++) {
                for (int x = 1; x <= i; x++)
                    f[i][j][k] = (f[i][j][k] + f[i - x][j][k] * co[i][x]) % mod;
                for (int x = 1; x <= j; x++)
                    f[i][j][k] = (f[i][j][k] + f[i][j - x][k] * co[j][x]) % mod;
                for (int x = 1; x <= k; x++)
                    f[i][j][k] = (f[i][j][k] + f[i][j][k - x] * co[k][x]) % mod;
            }
        }
    }
    

    f[i][j][k]f[i][j][k] 的含义
    当三个坐标分别有 i,j,ki,j,k11 需要添加时,交错添加这些 11 的总方案数。

    转移解释:

    • 第一个循环:在 xx 坐标上添加 xx11,从 ii 个位置中选 xx 个先添加(组合数 CixC_i^x),剩下的 ixi-x11j,kj,k 继续交错添加
    • 同理处理 y,zy,z 坐标

    这实际上是在计算 多重集排列数f[i][j][k]=(i+j+k)!i!j!k!f[i][j][k] = \frac{(i+j+k)!}{i!j!k!} 但这里用 DPDP 是为了避免大数阶乘(因为 i,j,k63i,j,k \le 63)。


    2. 容斥原理处理障碍

    将终点 (a,b,c)(a,b,c) 也当作一个"障碍"加入列表,排序(按三关键字)。

    g[i]g[i] 表示从 (0,0,0)(0,0,0) 到第 ii 个点 p[i]p[i],且不经过任何其他障碍点的路径数。

    初始: $g[i] = f[\text{pc}(p[i].x)][\text{pc}(p[i].y)][\text{pc}(p[i].z)]$ 即不考虑障碍时的总路径数。


    然后容斥:

    for (int j = 1; j < i; j++) {
        if ((p[j].x & p[i].x) != p[j].x || 
            (p[j].y & p[i].y) != p[j].y ||
            (p[j].z & p[i].z) != p[j].z)
            continue;
        
        g[i] = (g[i] + mod - g[j] * 
            f[pc(p[j].x ^ p[i].x)][pc(p[j].y ^ p[i].y)][pc(p[j].z ^ p[i].z)] % mod) % mod;
    }
    

    条件判断
    (p[j].x&p[i].x)==p[j].x(\text{p}[j].x \& \text{p}[i].x) == \text{p}[j].x 表示 p[j].xp[i].x\text{p}[j].x \subseteq \text{p}[i].x,即 p[j]\text{p}[j]p[i]\text{p}[i] 的路径上。

    容斥
    g[i]g[i] 中减去:先走到 p[j]\text{p}[j](不经过其他障碍),再走到 p[i]\text{p}[i] 的方案数。

    p[j]\text{p}[j]p[i]\text{p}[i] 的路径数 ==
    $f[\text{pc}(\text{p}[i].x \oplus \text{p}[j].x)][\text{pc}(\text{p}[i].y \oplus \text{p}[j].y)][\text{pc}(\text{p}[i].z \oplus \text{p}[j].z)]$

    因为 p[j]p[i]\text{p}[j] \subseteq \text{p}[i],所以异或得到的是需要新增11 的个数。


    3. 复杂度分析

    • 预处理 ffO(643×64×3)5×107O(64^3 \times 64 \times 3) \approx 5\times 10^7 可接受
    • 容斥 DPDPO(o2)O(o^2)o104o \le 10^4,所以 O(108)O(10^8) 有点紧但可行
    • 空间:O(643+o)O(64^3 + o)

    4. 样例验证

    样例:

    1 1 1
    0
    

    n=1n=1,没有障碍,终点 (1,1,1)(1,1,1)

    • pc(1)=1\text{pc}(1)=1(二进制 111111
    • f[1][1][1]f[1][1][1] 表示在三个坐标上各添加 1111 的交错顺序数
    • 三个 11 的排列:3!=63! = 6,但每个坐标内的 11 顺序固定,所以就是 66 种交错顺序

    输出 66,符合样例。


    总结

    这道题的核心技巧:

    1. 二进制包含关系按位添加 11 的顺序问题
    2. 三维独立性多重集排列数
    3. 容斥原理处理障碍
    4. 异或运算计算需要新增的 11 的个数

    通过将大范围坐标 (1018\le 10^{18}) 转化为 popcount 的小范围问题,实现了高效计算。

    • 1

    信息

    ID
    3699
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者