题意简述
给定一个长度为 (200,000) 的数组 (a),编号从 (0) 开始,初始时 (a_0=A,a_1=B),但你不知道 (A) 和 (B)
你可以执行不超过 (200,000) 次操作,每次操作如下两种:
(1)+ i j k
:让 (a_kleftarrow a_i+a_j)
(2)< i j k
:让 (a_kleftarrow a_i<a_j)
保证 (0le A,Ble 10^9),在任何时候 (a) 数组的元素都必须在 ([0,10^{19}]) 内
输出一个操作序列(注意此题无输入),使得所有操作结束之后,(a_2=A imes B)。
Solution
首先我们需要搞出 (1),这个利用 (a_{199999}<a_0) 即可直接得到。(a_0=0) 另当别论。
基本操作之一:两个 (0/1) 值的非和与运算
非:( ext{not }x=x<1)
与:(x ext{ and }y=1<x+y)
基本操作之二:根据 (0/1) 状态进行赋值
这好像没有什么好做法,但我们可以实现让 (x) 变成 (egin{cases}2^z & y=1\0 & y=0end{cases})(注意这个 (z) 是已知的,不是数组内的元素)。
可以视为 (xleftarrow 2^z imes y),故把 (x) 赋成 (y) 之后自加 (z) 次即可。
基本操作之三:二进制分解
即把 (x) 二进制分解的结果保存在 (b_{0dots 30}) 内。
记录一个临时变量初始 (y=0),然后从高到低位考虑,把 (b_i) 设定为 ( ext{not }(x<y+2^i)),然后根据 (b_i) 的值为 (0) 或 (1) 来决定是否要将 (y) 加上 (2^i),可以使用基本操作二。
总做法
有了三个基本操作之后,思路就比较自然了。
把 (a_0) 和 (a_1) 分别二进制分解后做个卷积((0/1) 值的相乘可用 ( ext{and}))得到答案的 (60) 位二进制表示之后依次加到 (a_2) 内即可。
不难发现,当 (a_0=0) 时上面的算法可以得出正确结果。操作次数为 (O(log^2(10^9)))。
Code
#include <bits/stdc++.h>
const int ZERO = 199998, ONE = 199999, N = 2e5 + 5;
int tot, a[N], b[N], c[N];
char ty[N];
void push(char t, int x, int y, int z)
{
ty[++tot] = t; a[tot] = x; b[tot] = y; c[tot] = z;
}
void make(int x, int y, int c)
{
push('+', y, ZERO, x);
for (int i = 1; i <= c; i++) push('+', x, x, x);
}
void NOT(int x) {push('<', x, ONE, x);}
void AND(int x, int y, int z) {push('+', x, y, z); push('<', ONE, z, z);}
void bin(int x, int offset)
{
push('+', ZERO, ZERO, x + 3);
for (int i = 30; i >= 0; i--)
{
push('+', x + 3, 100 + i, x + 5);
push('<', x, x + 5, offset + i);
NOT(offset + i); make(x + 5, offset + i, i);
push('+', x + 3, x + 5, x + 3);
}
}
int main()
{
push('<', ZERO, 0, ONE);
push('+', ZERO, ONE, 100);
for (int i = 1; i <= 30; i++) push('+', 99 + i, 99 + i, 100 + i);
bin(0, 1000); bin(1, 2000);
for (int i = 0; i <= 30; i++) for (int j = 0; j <= 30; j++)
AND(1000 + i, 2000 + j, 2500), push('+', 2500,
3000 + i + j, 3000 + i + j);
for (int i = 0; i <= 60; i++) make(4000, 3000 + i, i),
push('+', 2, 4000, 2);
std::cout << tot << std::endl;
for (int i = 1; i <= tot; i++) printf("%c %d %d %d
", ty[i],
a[i], b[i], c[i]);
return 0;
}