省选备战报告 第零辑 分块与根号平衡
本笔记仅仅记录重点思路,详细解题过程请参阅原题题解
难度从低到高为
- NÄIVE:有效思考时间少于十分钟
- EASY:能够完全独立得出
- MEDIUM EASY:需要题解提供关键思路跨越
- MEDIUM:需要查看题解的较多思路
- HARD:必须查看题解、并用长时间理解
- HELL:花费极长时间理解,非常难以复现
带有加号表示实现细节较多、需要格外注意。
完全不会做的题目不包括在难度列表中
正文
T0 [SD&SXOI2022] Day1T1 整数序列
Tag
根号分治、复杂度分析、暴力
带 \(\sqrt{\log}\) 做法:MEDIUM(思维中等;细节中等;代码中等)
严格根号做法:MEDIUM+(思维中等;细节多;代码长)
解题要点
为何想到根号分治
每次提问中相互影响的仅有两种数据,且若规模相差悬殊,时间只取决于较小的那一个。
根号分治的特点在于,按照数量将原始数据分类。其中小块受到大小限制,大块受到个数限制。思维的关键点在于小对大的处理。
处理时利用小块数量少的特点,将此特点转化为搜索空间小的优势。
时间复杂度分析
由于大对小时间复杂度取决于小块的长度,那就尽量把最长的小块多问几次。所以当假设有 \(K\) 个大块, \(k\) 个小块时,先用最长的小块挨个问一遍大块,再用次大的、次次大的……以此类推。合起来,就是用最大的 \(\frac{q}{K}\) 个小块向每个大块各问一遍。而最强的情况下就是没有落下的小块,\(k=\frac{q}{K}\) .
接下来更进一步,每处理一个询问所需要的时间是【扫描所有 \(O(\text{小块长度})\) 个点 \(\times\) 在 set
中查找】,总复杂度为:
\(l_i\) 表示小块长度, \(L_i\) 表示大块长度
放缩,上式一定小于
化简后可得
也就是
不严格根号做法
小对小直接暴力,大对大也直接暴力,考虑到大块数量少,后者可以记忆化,这两部分耗时 \(O(qB + \frac{n^2}{B})\) . 小对大的情况下筛选出有效点(对于小块的每个点,分别向前向后找到一个还没有被这一过程选过的大点),然后用有效点暴力,时间复杂度上面分析过了。
因此总复杂度为 \(O(qB+\frac{n^2\log n}{B})\) ,由均值不等式可得 \(B\) 应取 \(\sqrt{\frac{n^2\log n}{q}}\) . 总复杂度为 \(O(n\sqrt{q}\cdot\sqrt{\log n})\) ,由于最后的 \(\sqrt{\log n}\) 很小,所以把 \(B\) 稍稍取小一点就足够通过本题。
严格根号做法
上一种做法中,为了筛出所有的有效点,需要采用 set
维护有效点的区间,考虑如何移除掉set
代码
T1 [ZJOI2022] Day2T2 众数
Tag
根号平衡、复杂度分析
难度:MEDIUM(思维中等;细节少;代码中等)
解题要点
为何判定为根号分治
一般有有关于“众数”、“出现次数”的题目都应想到根号分治,因为这种题目需要处理颜色个数类的信息。
如何转化问题
“加上任意数”这种条件可以直接忽略,因为这种操作可以把任意数转化为任意数。问题的本质是把区间分成两段,并在内外各选出一个数,使得这两个数的出现次数总和是所有情况中最大的。
进一步,我们发现对答案产生贡献的仅有这两个数,并且它们也一定分别是内区间与外区间的众数(若不是的话,取众数更优)。这样问题表现出了显著的根号平衡特征。
经验:根号分治适用于“两两相对”/“需要考虑出现次数”类的问题
“小对大”时间复杂度分析
在处理大对小的情况时,我们需要枚举大块 \(x\) 并在内层枚举所有小块 \(y\) 并对小块构成的纯净区间求前缀和。
纯净区间,即把颜色为 \(y\) 的所有点单独拉出来组成的区间。
其时间复杂度并非
而应是
这是因为小块的个数不能按照 \(O(n)\) 处理。
小对小处理
大对小的情况下处理外层枚举大块前缀和即可,小对小的情况下,考虑到小块最多的元素个数也只有 \(\sqrt{n}\) 级别,并且计算贡献的时候我们完全不需要知道两数的具体取值。所以,枚举内区间众数的出现次数 \(K\) 即可。这一层的时间复杂度为 \(\sqrt{n}\) .
内循环需要枚举所有的众数出现次数为 \(K\) 的区间,并计算出此时外区间众数的出现次数。
T2 [CF1039D] You are given a tree
Tag
贪心及其证明、根号平衡、二分
难度:MEDIUM EASY(思维中等;细节少;代码短)
解题要点
为什么贪心是对的
本题的 \([1,\sqrt{n}]\) 部分需要用到朴素的贪心处理 \(\sqrt{n}\) 遍,每次解决 “在一棵树上最多能画几条长度为 \(k\) 的不相交链” 这样一个问题。
而这个问题可以 \(O(n)\) 贪心解决,具体来说,每个点记录“空余链长”,也就是从它开始向下数最长的还未被占用的链长。
对于每一个点,判断它儿子中【空余链长最长、次长的两个】能否放下一条长度为 \(k\) 的链。如果能,就把这个点的空余链长记录为 \(0\) ;如果不能,空余链长记录为儿子中空余链长最长的再加一。边界条件为【叶节点的空余链长为 \(1\) 】。
为什么是对的呢?考虑决策包容性。假设存在一个点 \(x\) ,它的两个儿子既可以支持一条通过 \(x\) 而不向上延伸的链,但最优解中 \(x\) 被一条连向父亲的链通过(没有利用上儿子的孔空余链长),那么我们可以把这条链放下来,充分利用儿子提供给它的空间。
同时,如果只看 \(x\) 的上方,最优解中的排布方式还能实现,并且还能获得额外的排布方式;如果只看 \(x\) 的下方,排布方式根本没有变化。这样,我们证明了 “把链尽量放下来” 完全包容了最优解。进一步也就证明了贪心的正确性。
为何考虑到根号平衡
考虑数值不同的答案的分布情况,发现后半部分出现大量答案重叠,猜测以根号为分界线。
后半部分的做法
这一部分有点类似于数论分块。
我们发现最后的 \(n-\sqrt{n}\) 个位置分了 \(\sqrt{n}\) 个答案数值,那么一定会有重复的。如何确定重复的区域呢?可以使用二分,首先枚举答案 \(k\) ,然后对于每个 \(k\) 二分查找此时最长的链长度,check
函数可以利用刚刚的贪心实现。
为什么是二分?因为答案随链长的增加单调不增,具体来说,如果能放下 \(t\) 条长度为 \(k\) 的链,那么没有理由放不下同样 \(t\) 条长度更短的。
把两个部分合起来,时间复杂度为 \(O(nB + \frac{n^2\log n}{B})\) 因此可以把块长改为 \(\sqrt{n\log n}\) .