原题地址 。
— 第 7 天:实验室 —
你感谢了头足类动物的帮助,离开了垃圾压缩机,发现自己身处北极研究区熟悉的走廊中。
根据一个写着"传送器中心"的大标志,他们似乎在研究传送;你忍不住自己尝试了一下,踏上了那个巨大的黄色传送器平台。
突然,你发现自己在一个陌生的房间里!这个房间没有门;唯一的出路就是传送器。不幸的是,传送器似乎在泄漏魔法烟雾。
由于这是一个传送器实验室,周围散落着许多备用零件、手册和诊断设备。连接上一个诊断工具后,它很有帮助地显示了错误代码 0H-N0,这显然意味着其中一个快子歧管出现了问题。
你很快找到了快子歧管的图表(你的谜题输入)。一束快子束从标记为 S 的位置进入歧管;快子束总是向下移动。快子束可以自由通过空的空间(.)。然而,如果快子束遇到一个分离器(^),光束会停止;取而代之的是,从分离器的紧邻左侧和紧邻右侧各自继续发出一束新的快子束。
例如:
.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
在这个例子中,入射的快子束(|)从 S 向下延伸,直到遇到第一个分离器:
.......S.......
.......|.......
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
此时,原始光束停止,从分离器发射出两束新光束:
.......S.......
.......|.......
......|^|......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
这些光束继续向下,直到遇到更多分离器:
.......S.......
.......|.......
......|^|......
......|.|......
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
此时,两个分离器总共只产生三束快子束,因为它们都把快子注入到它们之间的同一位置:
.......S.......
.......|.......
......|^|......
......|.|......
.....|^|^|.....
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
这个过程一直持续,直到所有快子束都到达分离器或离开歧管:
.......S.......
.......|.......
......|^|......
......|.|......
.....|^|^|.....
.....|.|.|.....
....|^|^|^|....
....|.|.|.|....
...|^|^|||^|...
...|.|.|||.|...
..|^|^|||^|^|..
..|.|.|||.|.|..
.|^|||^||.||^|.
.|.|||.||.||.|.
|^|^|^|^|^|||^|
|.|.|.|.|.|||.|
为了修复传送器,你首先需要了解快子歧管的光束分离特性。在这个例子中,快子束总共被分离了 21 次。
分析你的歧管图表。光束将被分离多少次?
你的谜题答案是 1658。
此谜题的第一部分已完成!它提供了一颗金星:*
— 第二部分 —
完成对歧管的分析后,你开始修复传送器。然而,当你打开传送器的侧面更换损坏的歧管时,你惊讶地发现这不是一个经典的快子歧管——它是一个量子快子歧管。
使用量子快子歧管时,只有单个快子粒子被送入歧管。快子粒子会同时走每个遇到的分离器的左路径和右路径。
由于这不可能实现,手册推荐了量子快子分离的多世界诠释:每当一个粒子到达分离器时,实际上时间本身发生了分裂。在一个时间线中,粒子向左走;在另一个时间线中,粒子向右走。
为了修复歧管,你真正需要知道的是一个单粒子完成其所有可能的旅程后,有多少个时间线是活跃的。
在上面的例子中,存在许多时间线。例如,有一个粒子总是向左走的时间线:
.......S.......
.......|.......
......|^.......
......|........
.....|^.^......
.....|.........
....|^.^.^.....
....|..........
...|^.^...^....
...|...........
..|^.^...^.^...
..|............
.|^...^.....^..
.|.............
|^.^.^.^.^...^.
|..............
或者,有一个粒子在每个分离器处交替向左和向右走的时间线:
.......S.......
.......|.......
......|^.......
......|........
......^|^......
.......|.......
.....^|^.^.....
......|........
....^.^|..^....
.......|.......
...^.^.|.^.^...
.......|.......
..^...^|....^..
.......|.......
.^.^.^|^.^...^.
......|........
或者,有一个粒子最终到达与交替时间线相同的点,但走了一条完全不同的路径到达那里的时间线:
.......S.......
.......|.......
......|^.......
......|........
.....|^.^......
.....|.........
....|^.^.^.....
....|..........
....^|^...^....
.....|.........
...^.^|..^.^...
......|........
..^..|^.....^..
.....|.........
.^.^.^|^.^...^.
......|........
在这个例子中,粒子最终总共有 40 个不同的时间线。
将量子快子分离的多世界诠释应用到你的歧管图表上。一个单粒子最终会出现在多少个不同的时间线上?
解题思路,
第一问,看起来很像一个异或操作,快子和分离器两个1在同一个列相遇变成0,0和0还是0,后来仔细一看不是异或,因为我要0遇到1还是0,请教DeepSeek后它给出了正确的操作表达式:x & (~y)
SQL如下:
with recursive t as(
select
'.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............' t)
, b as(select row_number()over()rn ,translate(b, '.S^', '011') b from(select unnest(string_split(t, chr(10)))b from t)where instr(b, 'S')>0 or instr(b, '^')>0)
,a as(select 1 lv, b::BITSTRING::int m from b where rn=1
union all
select 1+lv, m & ~( b::BITSTRING::int)| (b::BITSTRING::int <<1) |(b::BITSTRING::int >>1) from a, b
where lv+1=rn)
, o as(select lv, m::bitstring v,bit_count(v)bc from a)
, p as(select lv, v, bc, lead(v)over(order by lv)&v l ,bit_count(l)bc2 from o)
select sum(bc)-sum(bc2) from p where l is not null;
对于示例数据,它正确得出了分裂次数21, 但是正式输入数据一行有140字符,超过了DuckDB的hugeint范围,所以让DeepSeek把上述SQL改写成Python程序,修改几处BUG后如下所示。
它添加的注释很好地说明了算法,就不多解释了。
# 原 SQL 中的递归 CTE 部分用循环和列表处理来模拟
# 1. 原始数据
data = """.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
..............."""
# 2. 将数据按行分割,并转换为二进制整数
lines = data.split('\n')
# 处理每一行:将 '.'、'S'、'^' 转换为二进制数字
# 规则:'.' -> 0, 'S'/'^' -> 1
binary_rows = []
for line in lines:
if 'S' in line or '^' in line:
bin_str = line.replace('.', '0').replace('S', '1').replace('^', '1')
binary_rows.append(int(bin_str, 2)) # 转换为整数
# 3. 模拟递归计算(实际上是逐行迭代计算)
lv = 1
m = binary_rows[0] # 第一行
results = [(lv, m, bin(m))] # 存储每行结果 (层级, 整数, 二进制字符串)
# 处理第 2 行到最后行
for i in range(1, len(binary_rows)): # 确保不超过数据行数
lv += 1
b = binary_rows[i] # 当前行的二进制整数
# 核心公式: m & ~b | (b << 1) | (b >> 1)
m = (m & ~b) | (b << 1) | (b >> 1)
results.append((lv, m, bin(m)))
# 4. 计算 bc (bit_count) 和 bc2
from math import log2
def bit_count(num):
"""计算整数的二进制表示中 1 的个数"""
return bin(num).count('1')
# 将结果转换为便于处理的列表
o = [(lv, v, bit_count(v)) for lv, v, _ in results]
# print(o)
# 计算相邻两行之间的重叠比特数
total_bc = 0
total_bc2 = 0
for i in range(len(o) - 1):
lv, v, bc = o[i]
next_lv, next_v, next_bc = o[i + 1]
# 当前行与下一行的位与结果
l = v & next_v
bc2 = bit_count(l)
total_bc += bc
total_bc2 += bc2
# 5. 最终计算结果
result = total_bc - total_bc2
print(f"结果: {result}")
将它用于正式输入,通过了。
第二问有些复杂,SQL不会写,让DeepSeek帮助给出python代码,但提示了好多次,也得不到正确结果,最后我手工计算例子的每一行,总结出具体操作步骤,提示他
对于下图
第4层: 不一致 (计算=19, 给定=13)
给定: [(3, 1), (5, 4), (7, 3), (8, 3), (9, 1), (11, 1)]
计算: [(3, 1), (5, 4), (7, 6), (8, 3), (9, 4), (11, 1)]
符号层3: ....|^|^|^|....,所有|的路径数从左到右分别为 1,3,3,1
符号层4: ...|^|^|||^|...
你应该先从第4层删除所有的|,把他们都恢复为“.”,然后从第4层第1个出现的
^开始分析,它的正上方是第3层的第一个|,所以分叉,在^左侧1格位置放上|,它的路径数=第3层的第一个|路径数,然后在^右侧1格位置放上|,它的路径数先暂时算上第3层的第一个|路径数1,然后分析第4层第2个出现的^,它的正上方是第3层的第2个|,所以分也分叉,把第3层的第2个|的路径数加到左侧的|,即刚才暂时算上的|,所以第4行第2个|最终路径数=1+3=4,再在第4层第2个出现的^右侧放上|,它的路径数先暂时算上第3层的第2个|路径数,注意在处理第4行第3个^时还发现,它没有接在第3层第3个|正下方,所以在第3层第3个|正下方的位置放置一个直通的|,路径数3,依次类推,直到第4行的全部^处理完毕。
终于写出来了
def construct_paths_from_symbols(symbol_layers):
rows = len(symbol_layers)
cols = len(symbol_layers[0])
# 存储每一层 | 的位置和路径数
result_pipes = []
# 第0层:处理 S
layer0_pipes = []
for i, ch in enumerate(symbol_layers[0]):
if ch == 'S':
layer0_pipes.append((i, 1)) # S 视为 |,路径数=1
result_pipes.append(layer0_pipes)
# 从第1层开始处理
for r in range(1, rows):
current_symbols = symbol_layers[r]
# 获取上一层 | 的路径数映射
prev_pipes = {pos: val for pos, val in result_pipes[r-1]}
# 初始化当前层路径数映射(只记录 | 的位置)
path_map = {}
# 第一步:处理每个 ^ 的分叉
for i, ch in enumerate(current_symbols):
if ch == '^':
# 检查正上方是否是 |
above_pos = i
if above_pos in prev_pipes:
path_val = prev_pipes[above_pos]
# 左侧位置(如果位置有效)
left_pos = i - 1
if left_pos >= 0:
path_map[left_pos] = path_map.get(left_pos, 0) + path_val
# 右侧位置(如果位置有效)
right_pos = i + 1
if right_pos < cols:
path_map[right_pos] = path_map.get(right_pos, 0) + path_val
# 第二步:处理直通(上一层的 | 直通到正下方)
for prev_pos, prev_val in prev_pipes.items():
# 检查正下方位置
below_pos = prev_pos
if below_pos < len(current_symbols):
# 如果正下方不是 ^(因为 ^ 已经处理过分叉了)
if current_symbols[below_pos] != '^':
# 直通到正下方
path_map[below_pos] = path_map.get(below_pos, 0) + prev_val
# 第三步:收集当前层所有 | 的位置和路径数
# 只有 path_map 中有路径数的位置才有 |
current_pipes = []
for pos in sorted(path_map.keys()):
if path_map[pos] > 0: # 路径数大于0的位置才有 |
current_pipes.append((pos, path_map[pos]))
result_pipes.append(current_pipes)
return result_pipes
def read_symbol_layers(filename):
symbol_layers = []
with open(filename, 'r') as f:
for i, line in enumerate(f):
line = line.strip()
if line and not all(ch == '.' for ch in line): # 跳过全.行
symbol_layers.append(line)
return symbol_layers
symbol_layers =read_symbol_layers('2507-input.txt')
# 构造路径并计算
constructed_pipes = construct_paths_from_symbols(symbol_layers)
"""
print("构造得到的 | 路径数:")
for i, pipes in enumerate(constructed_pipes):
print(f"第{i}层: {pipes}")
if pipes:
sum_val = sum(val for _, val in pipes)
print(f" 总和: {sum_val}")
else:
print(f" 总和: 0")
"""
# 输出最后一行的结果
print("\n=== 最后一行的结果 ===")
last_layer = constructed_pipes[-1]
#print("最后一行的 | 位置和路径数:")
#for pos, val in last_layer:
# print(f" 位置 {pos}: 路径数 = {val}")
total_paths = sum(val for _, val in last_layer)
print(f"\n最后一行的总路径数: {total_paths}")

1万+

被折叠的 条评论
为什么被折叠?



