[CF418E] Tricky Password 题解
着实是一道阴间题,或者说是一道神仙题。
首先发现这道题中构造下一行序列的方法比较奇妙,用上一行的出现次数来构造,我们考虑从这个构造方法以及它本身的核心意义上来证明一个至关重要的结论——除去第一行外,所有奇数行都相同,所有偶数行都相同。
如何证明这个结论呢,我们考虑因为第一行的特殊性,所以把它扣掉,其它的就不具有特殊性了,我们选择证明从第二行推到第三行,再从第三行推到第四行,如果能得到第四行和第二行相同,则可以证明成立。
我们发现因为构造方法的特殊性,令 \(rk_{i,j}\) 表示 \(i\) 这个数在第二行中第 \(j\) 次出现的位置,则满足 \(\forall i<i',\ rk_{i,j}<rk_{i',j}\),即 \(1\) 第 \(j\) 次出现一定在 \(2\) 第 \(j\) 次出现之前,理由很简单,第二行中第 \(i\) 个 \(j\) 表示第一行整个位置是第 \(j\) 个出现了 \(i\) 次的数,那么上个结论就显而易见了,另一个结论是随着数越大,出现次数单调不递增。
利用这两个结论,我们就可以利用类似数学归纳法的方法来证明第四行和第二行相同了。
考虑第三行的中某个位置上是出现的第 \(i\) 个 \(x\),则表示第二行这个位置的数已经出现了 \(x\) 次,且这个数是第 \(i\) 个出现了 \(x\) 次的数,那么这个数就应该是 \(i\),是第 \(x\) 个 \(i\),因为出现了 \(x\) 次的数中,比 \(i\) 小的都在 \(i\) 前面出现过了,比它大的也都在后面。
这样的话就发现第二行的第 \(x\) 个 \(i\) 对应第三行的第 \(i\) 个 \(x\),同理也可以从第三行推到第四行,从第 \(i\) 个 \(x\) 重新推到第 \(x\) 个 \(i\),就证明完成了。
那么有了这个结论后我们就可以从维护不知道多少行减少到只维护三行了,第一行可以直接维护,第二行和第三行我们直接从定义入手维护。
考虑先维护第二行的结果,本质上就是直接维护每个数出现次数的前缀和,如果直接数组维护不仅空间会炸,时间也扛不住,所以考虑进行分块,分块预处理前缀出现次数,每次暴力继承上个块的答案,并统计自己块里的答案,每次修改就修改一个后缀,而每次询问就把最后的散块的信息暂时放到前面的块内,统计完后再消除影响就好了。
然后考虑维护第三行,其实是一样的,考虑第三行本质就是要维护第一行至少出现了 \(x\) 次的数的个数,然后找到第一行这个数对应出现几次,也就是在第二行的值,再在第三行查,其实维护起来也非常简单,修改也是后缀修改,查询方法也是一样的。
代码实现其实不是很难,直接用分块维护就好了,也不卡常。