P8988 Solution

· · 题解

在本题解中,约定 k=2^{13}=8192,所有数组下标均从 0 开始编号。

题意简述与分析

现有一个长度为 k 的数组 sgn,满足 sgn_i\in\{1,-1\},且已知 sgn_{k-1}=1,sgn_{k-2}=-1

对于一个长度为 k 的 01 串 S,定义 f(S)=\sum_{0\le i<k}[S_i=1]sgn_i 2^ig(x)f(x) 的反函数。

二进制加法的法则是“逢 21”,由定义可知,对于任意两个长度为 k 的 01 串 S,Tg(f(S)+f(T)) 的值就是对 ST 做“逢 21-1”的“二进制加法”后得出的结果,也可以发现,题目中的加法运算与这里的加法完全一致。(讲的不够清楚,但这一段非常重要)

同样,由于加法运算的存在,证明了 f(x) 存在反函数 g(x)

现每次询问要求给出两个长度为 k 的 01 串 S,T,交互库会返回 g(f(S)+f(T)),用尽量少的询问套出 sgn 数组。

题目补充:三个 Subtask 的 LIMIT 分别为 8200,5550,4096

Solution

定义 R=g(f(S)+f(T))

f(S)+f(T) 的第 i 位发生进位,且之后的所有位均为 0,则 R 的第 i 位后会出现一段连续的 1,其中最高位的 1 所在位与第 i 位同号,中间的 1 所在位与第 i 位异号。

对每一位分开询问即可,最大询问次数为 8190,可得 10 分。

在上一个做法中,我们让每次询问恰好发生一次进位,这样会大幅度浪费询问次数,考虑多进程询问。

考虑分块,一次进位要么只会影响该位所在的块内的部分,要么会发生“跨块”。如果某一个块发生“跨块”,那么这个块内的所有位会被全部做完,所以“跨块”最多会发生 \sqrt{k} 次,当跨块发生时停止处理后面的块即可。

询问上限 2\sqrt{k}\le 182,可以通过本题。

以上为标算的做法,接下来,我们要开启快乐的踩标之旅!

反过来考虑,如果我们令 S=11111111\dots 1111,T=00000000\dots 0001,得到的 R 必然为一段 1 后跟一段 0,其中最高位的 0 与最低位异号,其余的 0 与最低位同号。我们还可以发现,更高位的 1 还可以供我们多线程询问。

因此,对于当前要解决的区间 (l\sim r,d),其中 r+1\sim d-1r 同号,dr 异号,我们可以对 mid 做一次单点询问,对得到的最高位的 0 所在位 p 再做一次单点询问,设第二次询问得到的最高位的 0 在第 q 位,我们可以确定 mid\sim p-1mid 同号,p\sim q-1mid 异号,qmid 同号。同时,原区间被分为了两个区间 (l\sim mid,p)(q\sim r,d),子区间依然满足原区间的性质,由于中间的异号位充足,两个子区间不会对对方产生影响,多个不交的区间同时进行即可。

询问上限 2\log_2 k = 26,完成一般踩标。

我们想想当询问利用率达到极限会发生什么。

S=T=11111111\dots 1111,对于 R 某一位,若该位与下一位同号,则下一位会进 1,下一位会正常进位;若该位与下一位异号,则下一位会退 1,下一位不会进位,带来的影响就是再下一位必定为 0

因此,若 R 的第 i 位为 0,则它的上一位和上上位异号,它和上一位的关系不知道,对不知道的关系做一次统一询问即可。由于两个询问位之间必定有一组异号关系,按最原始的方法询问不会出现互相影响的问题。

询问上限 2\times 1 = 2,完成爆踩标算。