QOJ.ac

QOJ

Time Limit: 2 s Memory Limit: 512 MB Total points: 100

#13104. 硬件哈希

Statistics

Harry 在 Hlink 公司工作,该公司正在为 Hoogle 开发路由硬件。最近,他被要求为 HH-932 路由芯片编写哈希软件。

让我们描述一下 HH-932 的架构。该芯片拥有 4 兆字节($4 \times 2^{20}$ 字节)的只读闪存,可以包含芯片将要执行的程序和数据。该芯片的处理器有 256 个寄存器,命名为 r0r255,每个寄存器包含一个 32 位整数。在程序执行前,除 r0 外的每个寄存器都包含 0,而 r0 包含程序的输入。

该芯片还有一个特殊的寄存器,称为指令指针(instruction pointer)。程序存储在闪存中,初始时指令指针等于 0。程序的执行过程如下:解析并执行指令指针所指向地址处的指令。如果指令没有导致跳转,指令指针将增加所解析指令的大小,从而指向刚执行指令之后的内存字节。

Harry 的任务是为给定的 $n$ 个整数集合 $A = \{a_1, a_2, \dots, a_n\}$ 创建一个非常快速的哈希函数,映射到 $0$ 到 $2n - 1$ 之间的整数集合。该函数的计算必须在最多 30 条指令内终止。哈希函数不能有冲突。形式上,需要编写一个程序,满足以下条件:

  • 如果程序使用集合 $A$ 中的一个整数执行,它必须在执行最多 30 条指令后终止,并返回 $0$ 到 $2n - 1$ 之间的值。
  • 对于 $A$ 中的任意两个不同值 $a_i$ 和 $a_j$,返回的值必须不同。

Harry 不擅长底层编程,所以他向你求助。他发给你一张 HH-932 芯片的可能指令及其十六进制操作码的表格。他没有提供注释,你在互联网上搜索了文档,没有找到,但发现了以下补充说明:

  • 所有寄存器都包含 32 位整数。
  • 加法、减法和位运算不区分整数是有符号还是无符号。
  • 条件跳转将寄存器解释为有符号整数。
  • 乘法或除法的结果是一个有符号的 64 位整数,保存到两个寄存器中。获得结果低位的寄存器将其存储为无符号整数。
  • 除法和取模运算使用 64 位整数作为被除数,低位被解释为无符号,高位被解释为有符号。除数是有符号的。
  • 有符号整数的除法和取模运算方式与 x86 架构相同。
  • 芯片内存中的所有整数都以低字节在前(小端序)的方式保存。

你必须创建芯片闪存的内容,以便在它作为程序执行后,计算并返回所需的哈希函数。

对于集合 $A$ 中的任何输入,你的程序不得访问 4M 范围之外的内存,且不得除以零。指令指针也不得超出 4M 范围。

指令表

指令 大小 操作码 指令功能
nop 1 字节 00 无操作
add 4 字节 01 r1 r2 r3 r3 := r1 + r2
sub 4 字节 02 r1 r2 r3 r3 := r1 - r2
mul 5 字节 03 r1 r2 r3 r4 (r3, r4) := r1 * r2r3 存低位,r4 存高位
div 6 字节 04 r1 r2 r3 r4 r5 (r3, r4) := (r1, r5) div r2r1 存被除数低位,r5 存被除数高位,r3 存商低位,r4 存商高位
mod 5 字节 05 r1 r2 r3 r4 r3 := (r1, r4) mod r2r1 存被除数低位,r4 存被除数高位
and 4 字节 10 r1 r2 r3 r3 := r1 and r2
or 4 字节 11 r1 r2 r3 r3 := r1 or r2
xor 4 字节 12 r1 r2 r3 r3 := r1 xor r2
neg 2 字节 20 r1 r1 := -r1
not 2 字节 21 r1 r1 := ~r1
load 3 字节 30 r1 r2 r1 := memory[r2],从地址 r2 开始的 4 字节复制到 r1,低字节在前
put 6 字节 31 r1 b0 b1 b2 b3 r1 := (b0, b1, b2, b3)b0 为低字节,b3 为高字节
jmp 5 字节 40 b0 b1 b2 b3 跳转到地址 (b0, b1, b2, b3)
jz 6 字节 41 r1 b0 b1 b2 b3 r1 == 0 则跳转到地址 (b0, b1, b2, b3)
jnz 6 字节 42 r1 b0 b1 b2 b3 r1 != 0 则跳转到地址 (b0, b1, b2, b3)
jg 6 字节 43 r1 b0 b1 b2 b3 r1 > 0 则跳转到地址 (b0, b1, b2, b3)
jge 6 字节 44 r1 b0 b1 b2 b3 r1 >= 0 则跳转到地址 (b0, b1, b2, b3)
jl 6 字节 45 r1 b0 b1 b2 b3 r1 < 0 则跳转到地址 (b0, b1, b2, b3)
jle 6 字节 46 r1 b0 b1 b2 b3 r1 <= 0 则跳转到地址 (b0, b1, b2, b3)
ret 1 字节 ff 程序返回,返回值为 r0

输入格式

输入文件的第一行包含 $n$ ($1 \le n \le 100\,000$)。第二行包含 $n$ 个不同的整数 $a_1, a_2, \dots, a_n$ ($1 \le a_i \le 10^9$)。

输出格式

输出芯片闪存的内容。你可以输出 1 到 4\,194\,304 之间的任意字节数。内存的其余部分填充为零。每个字节必须打印为两位十六进制数字。不要打印空格。

请仅输出程序所需的内存前缀,不要输出末尾的零,以加快测试速度。

样例

输入 1

3
2 3 9

输出 1

3101040000000500010003ff

输入 2

2
6 10

输出 2

300000ff00000000000001000000

说明

在第一个样例中,程序的解析和执行过程如下:

操作码 指令 执行操作 说明
31 01 04 00 00 00 put r1 4 r1 := 4 r0 = a_i, r1 = 4
05 00 01 00 03 mod (r0, r3) r1 r0 r0 := (r0, r3) mod r1 r0 = a_i mod 4, r1 = 4
ff ret return r0 返回 a_i mod 4

在第二个样例中,程序的解析和执行过程如下:

操作码 指令 执行操作 说明
30 00 00 load r0 r0 r0 := memory[r0] a_i = 6r0 = 0,若 a_i = 10r0 = 1
ff ret return r0 返回 0 或 1

注意,除了程序代码外,第二个样例中的内存还包含一些用作返回值的额外数据。

Discussions

About Discussions

The discussion section is only for posting: General Discussions (problem-solving strategies, alternative approaches), and Off-topic conversations.

This is NOT for reporting issues! If you want to report bugs or errors, please use the Issues section below.

Open Discussions 0
No discussions in this category.

Issues

About Issues

If you find any issues with the problem (statement, scoring, time/memory limits, test cases, etc.), you may submit an issue here. A problem moderator will review your issue.

Guidelines:

  1. This is not a place to publish discussions, editorials, or requests to debug your code. Issues are only visible to you and problem moderators.
  2. Do not submit duplicated issues.
  3. Issues must be filed in English or Chinese only.
Active Issues 0
No issues in this category.
Closed/Resolved Issues 0
No issues in this category.