CF93C Azembler
题目描述
在“Search Ultimate”程序因在文本中查找字符串时失败后,Igor K. 开始思考:“为什么我的程序这么慢?”在他仔细检查自己的代码后,说道:“我的代码没有错误,但我知道怎么让 Search Ultimate 更快!”于是他从书架上取下一本大书。封面写着《Azembler. Principally New Approach》。
Igor K. 仔细翻阅了这本书后明白了,原来你可以让乘法执行得快几十倍。“Search Ultimate 会比以往任何时候都更快!”——他高兴地叫道,并开始着手工作。
现在让我们澄清一下 Igor 的想法。问题在于编译器生成的代码远非完美。标准乘法的运行速度比书中提及的技巧慢得多。
Azembler 语言有 26 个寄存器(eax, ebx, ..., ezx)和两条指令:
- \[ $x$ \] — 返回位于地址 $x$ 的数值。例如,\[eax\] 返回存放在地址 eax 的数值。
- lea $x$ , $y$ — 把第二个参数 $y$ 的地址赋给第一个参数 $x$ 所指的寄存器。例如,“lea ebx, \[eax\]” 指令,将 eax 寄存器中的内容写入 ebx:首先执行 \[eax\] 操作,其结果是位于 eax 寄存器所存地址的某个值。但事实上我们并不需要这个值——下一步是 lea 操作,它会把 \[eax\] 的地址(即 eax 中的值)写入 ebx。
乍一看,第二种操作似乎毫无意义,但事实上可以写成:
lea ecx, \[eax + ebx\],
lea ecx, \[k\*eax\],
甚至
lea ecx, \[ebx + k\*eax\],
其中 $k$ 只能是 1、2、4 或 8。
最终,ecx 寄存器的值分别为 eax + ebx、k\*eax 和 ebx + k\*eax。然而,这样的操作执行速度要比通常的数值乘法快很多倍。通过使用若干此类操作,可以非常迅速地实现某个数乘以另一个数。当然,eax、ebx、ecx 都可以任意替换成其它寄存器。
例如,假设 eax 寄存器中有一个数,我们要将它乘以 41。这只需要 2 行指令:
lea ebx, \[eax + 4\*eax\] // 此时 ebx = 5\*eax
lea eax, \[eax + 8\*ebx\] // 此时 eax = eax + 8\*ebx = 41\*eax
Igor K. 感兴趣的问题是:最少需要多少条 lea 操作才能实现乘以给定的数 $n$?应该如何实现?你的任务就是帮助他解决这个问题。
初始时,eax 内存放待乘以 $n$ 的数,ebx 到 ezx 的所有寄存器的内容均为 0。最终,结果可以存放在任意寄存器中。
输入格式
输入包含唯一一个整数 $n$($1 \leq n \leq 255$),即 Igor K. 要实现的乘数。
输出格式
第一行输出最少需要的 lea 操作数 $p$。接下来的 $p$ 行输出该程序的 $p$ 条指令。
要求严格使用以下格式的指令输出(其中 $k$ 取 1、2、4、8,$x$、$y$、$z$ 为任意寄存器,允许取相同寄存器名):
lea x, \[y\]
lea x, \[y + z\]
lea x, \[k\*y\]
lea x, \[y + k\*z\]
注意命令行末不得有多余的空格。
说明/提示
由 ChatGPT 5 翻译