CF2109C1/2/3 Hacking Numbers
CF2109C1/2/3 Hacking Numbers
tag: 交互,构造,思维题
交互题。每组测试数据,给出一个数 \(n\)(\(1\le n\le10^9\)),并且有一个未知的数 \(x\)(\(1\le x\le10^9\))。
对 \(x\) 进行若干次操作,将 \(x\) 变成 \(n\),操作包括以下几种:
- \(\texttt{add}\ y\):令 \(res=x+y\),其中整数 \(y\) 满足 \(-10^{18}\le y\le10^{18}\)。
- 若 \(1\le res\le10^{18}\),则令 \(x\) 变成 \(res\),同时交互器返回 \(\texttt{1}\);
- 否则,\(x\) 的值不变,同时交互器返回 \(\texttt{0}\)。
- \(\texttt{mul}\ y\):令 \(res=x\cdot y\),其中整数 \(y\) 满足 \(1\le y\le10^{18}\)。
- 若 \(1\le res\le10^{18}\),则令 \(x\) 变成 \(res\),同时交互器返回 \(\texttt{1}\);
- 否则,\(x\) 的值不变,同时交互器返回 \(\texttt{0}\)。
- \(\texttt{div}\ y\):令 \(res=x/y\),其中整数 \(y\) 满足 \(1\le y\le10^{18}\)。
- 若 \(y\) 能整除 \(x\),则令 \(x\) 变成 \(res\),同时交互器返回 \(\texttt{1}\);
- 否则,\(x\) 的值不变,同时交互器返回 \(\texttt{0}\)。
- \(\texttt{digit}\):令 \(x=S(x)\),其中 \(S(x)\) 为 \(x\) 的数字根,即 \(x\) 的各个数位上的数之和。
各个 version 只有操作次数的限制不同。
Easy Version
操作次数不超过 \(7\) 次。
可以发现,由于 \(x\) 不超过 \(10^9\),\(\texttt{digit}\) 操作会将 \(x\) 限制到 \([1,81]\) 的范围内(最大为 \(S(999\,999\,999)=81\)),再做一次则会限制到 \([1,16]\) 的范围内(最大为 \(S(79)=16\))。
根据二分的思想,如果 \(\texttt{add}\ -\lfloor 16/2\rfloor=-8\) 操作返回 \(\texttt1\),则减完之后 \(x\in[1,8]\);如果返回 \(\texttt{0}\),则说明本来就有 \(x\in[1,8]\)。
因此,这样做可以将 \(x\) 的范围减半。\(\log_216=4\) 次之后,\(x\) 一定为 \(1\)。故执行操作:
digit
digit
add -8
add -4
add -2
add -1
add n-1
!
即可。
Medium Version
操作次数不超过 \(4\) 次。
见到数字根,我们可以想到 \(3\) 和 \(9\) 的倍数的性质:数字根分别也为 \(3\) 和 \(9\) 的倍数。
因此,先执行 \(\texttt{mul}\ 9\),再 \(\texttt{digit}\),那么 \(x\) 的取值范围为 \(\{9,18,27,36,45,54,63,72,81\}\)。
再执行一次 \(\texttt{digit}\),则一定有 \(x=9\)。
接着 \(\texttt{add}\ n-9\) 就完成了。
Hard Version
操作次数不超过 \(f(n)\) 次,其中 \(f(n)\) 是对于任意 \(x\),将 \(x\) 变成 \(n\) 的最少操作次数的最大值。
即:设 \(o=o_1,o_2,\cdots,o_k\) 为一操作序列,使得对于任意 \(x\),通过执行这一操作序列,都可以将 \(x\) 变成 \(n\),则 \(f(n)=\min\limits_{o}k\)。
事实上,\(10^d-1=\overline{\underbrace{999\cdots999}_{\text{d 个 9}}}\) 都有类似的性质:对于所有 \(x\in[1,10^d]\),有 \(S((10^d-1)x)=9d\)。
证明:由于
\[(10^d-1)x=x\cdot10^d-x=(x-1)\cdot10^d+10^d-x=(x-1)\cdot10^{d}+[(10^d-1)-(x-1)], \]设 \(x-1=\overline{a_1a_2\cdots a_d}\)(可能有前导零),则
\[\begin{gathered} (x-1)\cdot10^d=\overline{a_1a_2\cdots a_d\underbrace{000\cdots0}_{\text{$d$ 个 $0$}}},\\ (10^d-1)-(x-1)=\overline{\underbrace{999\cdots9}_{\text{$d$ 个 $9$}}}-\overline{a_1a_2\cdots a_d}=\overline{(9-a_1)(9-a_2)\cdots(9-a_d)}, \end{gathered} \]故它们的和的第 \(i\) 位和第 \(i+d\) 位上数字之和为 \(9\),其中 \(1\le i\le d\),因此 \(S((10^d-1)x)=9d\)。
因此,\(999\,999\,999\) 的倍数的 \(S\) 值为 \(81\),故执行
mul 999999999
digit
add n-81
!
即可。
注意特殊情况:\(n=81\),此时不需要 \(\texttt{add}\ n-81\) 的操作。
为什么这样是最优的:
显然,开始时执行 \(\texttt{add}\)、\(\texttt{div}\) 或 \(\texttt{digit}\) 操作都不能使 \(x\) 变成一个确定的值。
并且,如果第一次 \(\texttt{mul}\) 操作中 \(y\ne999\,999\,999\),那么令 \(x=1\) 和 \(x=999\,999\,999\),得到
即 \(x\) 会分别变成 \(x\le80\) 和 \(x=81\),不可能是一个确定的值。
因此 \(\texttt{mul}\ 999\,999\,999\) 之后 \(\texttt{digit}\),一定有 \(x=81\),是唯一的确定且最优的操作序列。
代码:320174921

浙公网安备 33010602011771号