好像本题不能交题解?
这里给出一种所有子任务下询问问题 2 的次数都不超过 13 的做法。
朴素的做法是:假设我们想要知道 [1,m] 内的数分别在什么位置,我们可以先询问一次问题 2 来知晓 (2m,m] 的位置集合,再借助问题 1 用数 m+1 去对这些位置上的数分别取模,从而确定出它们各自的值是多少(m+1 对 (2m,m] 内的任意数取模的结果都是不一样的),最后再通过递归来进一步求 [1,2m] 内的数的位置。这样,我们只需要在最开始先询问一次问题 2 来确定出 n 的位置,然后利用上述做法求 [1,n−1] 内的数的位置即可得到整个排列。该方法所需的问题 2 的询问次数为 1+logn,当 n=5×104 时为 16。
考虑如何优化一次询问。注意到 5mod1=0,5mod2=1,5mod3=2,而 49999 不断(整)除以 2 恰好会得到 6,也即:当我们想要知道 [1,6] 内的数分别在什么位置时,我们先确定出 4,5,6 的位置,之后无需再继续递归,而是用 5 分别对剩下三个未确定位置上的数取模,利用模数就能将 1,2,3 的位置判断出来。这样就节省了一次询问,即在最后一个子任务下只需 15 次询问 2 即可求出排列。这足以通过本题。
延续上面的思路:如果一个数 x 除以从 1 开始的一段连续自然数 1∼r 的余数均不相同,那么利用 x 就能够把 1∼r 的位置判断出来。又因为 xmod1=0,因此 xmod2 必然为 1,xmod3 必然为 2……即 xmodi=i−1(1≤i≤r)。写一份程序可以找到在 50000 以内满足这一性质的最佳数 x=27719,它对应的 r=12。也即:如果我们找到了 27719 的位置,那么当我们递归到 [1,m] 满足 m≤12 时就可以停止使用朴素做法,直接利用 27719 就可以确定出 1∼m 所有数的位置。这样当 n=5×104 时我们在朴素做法的基础上减少了三次递归,问题 2 的询问次数也降至了 logn−2=13。
利用 27719 这一特殊数,子任务 3 和 4 询问问题 2 的次数仍不能得到有效优化,因为这两个子任务的 n 达不到 27719。略微缩小查找范围,我们可以找到另一个特殊数 2519,它对应的 r=10。使用该数可以使子任务 3 的询问问题 2 的次数降至 12,子任务 4 的询问次数降至 11。