[R8D] Z形填数
- 难度 普及
- 时限 1s
- 空限 512m
- 分治递归
数据规模:。
思路
Z 形填数就是经典的 Z 阶曲线(Morton code)。把行号 和列号 (从 开始)的二进制位交错排开,就得到这个格子填入的数字( 基下标),加 即为答案。具体地,第 位上 的位放进结果的第 位、 的位放进第 位。
这是因为:每次分形时,列在低位的 决定左/右(红黄、蓝绿在 轴的区分),行在低位的 决定上/下;先列后行的顺序对应偶数位放 、奇数位放 。
共 个格子,每个格子的位交错是 。
复杂度:时间 ,空间 (用于输出)。
仓颉实现
import std.convert.*
import std.env.*
main(): Int64 {
let reader = getStdIn()
let n = Int64.parse(reader.readln().getOrThrow())
var size: Int64 = 1
for (_ in 0..n) {
size *= 2
}
let S = size
let out = StringBuilder()
for (r in 0..S) {
for (c in 0..S) {
var idx: Int64 = 0
var bit: Int64 = 0
while (bit < n) {
idx = idx | (((c >> bit) & 1) << (2 * bit))
idx = idx | (((r >> bit) & 1) << (2 * bit + 1))
bit += 1
}
out.append(idx + 1)
if (c < S - 1) {
out.append(" ")
}
}
out.append("\n")
}
print(out.toString())
return 0
}
要点:
- Z 形分形递归展开后,填入数字正是行列二进制位交错的结果,无需真的递归模拟。