07 矩阵路径求和
题目描述
构造一个 $n \times m$ 的矩阵($n \times m \leq 200$),每个单元格填入非负整数。对于 $q$ 次询问,每次给出一个非负整数 $S$,需要找到一条从 $(1,1)$ 到 $(n,m)$ 的路径,满足:
- 每个单元格至多被经过一次
- 路径上所有数字之和等于 $S$
思路分析
如何思考这个问题?
当我们第一次看到这个问题时,可能会尝试各种复杂的图论算法。但仔细分析会发现几个关键点:
- 数字范围很大:$S \leq 10^{18}$,但矩阵大小有限制($\leq 200$)
- 每个单元格只能经过一次:这意味着路径是唯一的,不能走回头路
二进制的启发
想到二进制表示是自然的:
- 任何整数 $S$ 都可以表示为 $2^{a_1} + 2^{a_2} + \cdots + 2^{a_k}$
- 如果我们能让路径”选择性地”经过某些单元格,每个单元格的值是 $2^i$,那么只要控制哪些 $2^i$ 被经过,就能拼出任意 $S$
这就是核心洞察:把 $S$ 拆成二进制位,路径经过第 $i$ 行代表取 $2^i$。
构造的难点与解决
但直接这样构造会遇到问题:如果每次都走同样的列,路径会重复经过同一个单元格。
解决方法是利用奇偶性:
- 用
flag标志位交替使用RR(向右向右)和LL(向左向左) - 这样虽然目的都是向右移动到中间列,但走的路径不同,避免重复
最终方案
- 矩阵用 $(n+1) \times 3$ 的形状,其中 $n = \lceil \log2(S{max}) \rceil$
- 每行中间放置 $2^i$,其余为 0
- 路径根据二进制位决定是否”绕路”取这个值
解题思路
核心思想:二进制表示
对于任意 $S \leq 10^{18}$,我们可以用二进制表示。关键发现是:
- $S$ 的二进制表示中第 $i$ 位为 1 时,我们需要在路径中添加 $2^i$
- $S$ 的二进制表示中第 $i$ 位为 0 时,我们不需要添加 $2^i$
矩阵构造
构造一个 $(n+1) \times 3$ 的矩阵,其中 $n$ 是最大查询值 $S_{max}$ 的二进制位数:
第 i 行 (0 ≤ i < n): 0 2^i 0
第 n 行: 0 0 0例如当 $n=3$ 时(对应 $S_{max}=7$):
0 1 0
0 2 0
0 4 0
0 0 0路径构造
从 $(1,1)$ 出发,对于 $S$ 的二进制每一位:
- 若第 $i$ 位为 1:先向右走到中间列(取到 $2^i$),再向下走
- 若第 $i$ 位为 0:直接向下走
最后根据标志位决定是否需要额外的向右移动到达终点。
代码实现
import sys
input = sys.stdin.readline
q = int(input())
S_list = [int(input()) for _ in range(q)]
n = max(S_list).bit_length() # 最大S的二进制位数
print(n + 1, 3)
for i in range(n):
print(0, 1 << i, 0)
print("0 0 0")
for S in S_list:
path = []
flag = 1 # 奇偶标志,决定RR还是LL
for i in range(n):
if (S >> i) & 1:
path.extend(['RR' if flag else 'LL', 'D'])
flag ^= 1
else:
path.append('D')
if flag:
path.append('RR')
print(''.join(path))复杂度分析
- 矩阵大小:$(n+1) \times 3 \leq 61 \times 3 = 183 \leq 200$ ✓
- 时间复杂度:$O(q \cdot n)$,其中 $n = \log2(S{max}) \leq 60$
- 空间复杂度:$O(1)$
代码说明
n = max(S_list).bit_length()计算最大查询值的二进制位数- 矩阵构造:前 $n$ 行中间列为 $2^0, 2^1, \ldots, 2^{n-1}$,最后一行全为 0
- 路径构造使用标志位
flag交替使用RR和LL,确保路径不重复经过单元格
07 矩阵路径求和
https://mingsm17518.github.io/2026/03/18/algorithm/solutions/2025_SDU_Star_Remake/07-matrix-path-sum/