手造 rand 太烂,换成mt19937
过了。
题意简述
你需要猜一个 $0$ 到 $n - 1$ 的排列 $\langle a_n\rangle$,每次可以询问二元组 $(x, y)$($x\neq y$) ,表示询问 $a_x | a_y$ 的值,其中 $|$ 为按位或。
$3\le n\le 2048$,询问次数不能超过 $4269$ 次。
主要思路
本题有许多做法,下面放送本人认为最妙的一种方法。
假设现在有两个可能是 0 的位置 $x$ 与 $y$,设 $A(x, y) = a_x | a_y$。
考虑现在新加入一个可能是 0 的位置 $z$,如何排除一个呢?
- 如果 $A(z, y) < A(x, y)$,则 $x > 0$,否则 $A(x, y) = y \le A(z, y)$ 矛盾。
- 如果 $A(z, y) > A(x, y)$,则同理 $z > 0$。
- 如果 $A(z, y) = A(x, y)$,则 $y > 0$,否则 $A(z, y) = z = x = A(x, y)$ 非排列。
每个数都会被查询 1 次,并且如果出现上述最后一种情况,还应额外查询 $(x, z)$。
然后就得到了两个可能是 0 的位置。如何确定哪个是 0?随机一个 $d$,询问 $(x, d)$ 与 $(y, d)$ 直到二者答案不同,小的那个即为 0。
最后再让每个数都与 0 询问一次来获得整个排列。
明明有比 $2n$ 多的查询次数,为什么总次数是正确的?容易证明当我们按随机顺序判断每个数是否可能为 0 时,出现最后一种状况的概率极小。同样地,判断最后两个数哪个是 0 时,期望询问次数也不大。有兴趣的读者可以自己尝试证明。
由此可见,利用随机算法获取优秀的复杂度是解题的常用技巧之一。在数据结构中,典型的示例是随机堆。
参考代码
注意找到两个可能是 0 的位置也要随机顺序,否则可能导致最后一种情况过多导致询问次数超限。
1 |
|