1 条题解
-
0
题目理解
我们在三维空间 中,从 走到 ,移动规则是:
- 当且仅当 (即 ,二进制包含关系)
- 同理 ,
有些点是障碍,求合法路径数,对 取模。
关键观察
1. 二进制包含关系的组合意义
如果 ,那么在二进制下, 的 的位置包含了 的所有 的位置。
从 到 的路径数,相当于在 比 多出的那些 位中,按任意顺序依次添加这些 。
设 的二进制中 的个数,
从 到 的路径数 将 个 按任意顺序添加的方案数
种(在 坐标上)。
2. 三维独立性与组合数
因为三个坐标的移动是独立的,所以从 到 的路径数
$f(\text{popcount}(x), \text{popcount}(y), \text{popcount}(z))$
三个坐标各自添加 的顺序方案数的乘积,但要考虑不同坐标间的交错顺序。
算法解析
1. 预处理组合数和 数组
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; } }这里 是组合数 。
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; } } }的含义:
当三个坐标分别有 个 需要添加时,交错添加这些 的总方案数。转移解释:
- 第一个循环:在 坐标上添加 个 ,从 个位置中选 个先添加(组合数 ),剩下的 个 和 继续交错添加
- 同理处理 坐标
这实际上是在计算 多重集排列数: 但这里用 是为了避免大数阶乘(因为 )。
2. 容斥原理处理障碍
将终点 也当作一个"障碍"加入列表,排序(按三关键字)。
设 表示从 到第 个点 ,且不经过任何其他障碍点的路径数。
初始: $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; }条件判断:
表示 ,即 在 的路径上。容斥:
从 中减去:先走到 (不经过其他障碍),再走到 的方案数。从 到 的路径数
$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)]$因为 ,所以异或得到的是需要新增的 的个数。
3. 复杂度分析
- 预处理 : 可接受
- 容斥 :,,所以 有点紧但可行
- 空间:
4. 样例验证
样例:
1 1 1 0,没有障碍,终点 :
- (二进制 有 个 )
- 表示在三个坐标上各添加 个 的交错顺序数
- 三个 的排列:,但每个坐标内的 顺序固定,所以就是 种交错顺序
输出 ,符合样例。
总结
这道题的核心技巧:
- 二进制包含关系 → 按位添加 的顺序问题
- 三维独立性 → 多重集排列数
- 容斥原理处理障碍
- 异或运算计算需要新增的 的个数
通过将大范围坐标 () 转化为 popcount 的小范围问题,实现了高效计算。
- 1
信息
- ID
- 3699
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者