多校联训分治专题
[ICPC2017 WF]Money for Nothing
因为赚取的差价就是等于时间之差与价格之差的乘积。
所以可以看成是平面上的问题。
建立一个直角坐标系,将时间作为横坐标,价格作为纵坐标。
然后将生产商和消费商的信息转为平面上的点,其中将生产商划为A类点,消费商划为 \(B\) 类点。
之后问题就成了在平面上 左下角为 \(A\) 类点 右上角为 \(B\) 类点 求最大的矩阵面积的问题。
先将 \(A\) 类点按坐标进行排序。
如果 \(A\) 类点其中的两点出现了上图的情况。
显然,由 \(a_1\) 点为左下角的矩阵一定不会比以 \(a_2\) 点为左下角的矩阵的面积更大。
所以可以排除 \(a_1\) 点,将 \(a_1\) 点从候选集合中删去。
之后是将 \(B\) 类点按坐标进行排序。
如果 \(B\) 类点其中的两点出现了上图的情况。
同样,由 \(b_1\) 点为右上角的矩阵一定不会比以 \(b_2\) 点为右上角的矩阵的面积更大。
所以我们可以将 \(b_1\) 点从候选集合中删去。
我们发现在排除所有无用的点之后,\(A\) 类点和 \(B\) 类点都呈现出 \(x\) 递增 \(y\) 递减的样子。
考虑优化:
在去除无用点后的任意两个 \(A\) 类点和任意两个 \(B\) 类点中。
设 \(a_1,b_2\) 围成的矩形是以 \(a_1\) 为左下角的矩形当中最大的那一个。
我们可以得到这样一个结论:
\(a_2\) 和 \(b_1\) 围成的矩形的大小一定小于 \(a_2\) 和 \(b_2\) 围成的矩形的大小。
由此我们就可以用决策单调性来优化,复杂度 \(O(n\log n)\) 。
点击查看代码
Gym 103202L Forged in the Barrens
#592. 新年的聚会
首先有一个结论:
对于一张 \(n\) 个点 \(m\) 条边的无向图,可以将点集划分为 \(O(\sqrt m)\) 个独立集
证明:
对于度数 \(≥\sqrt m\) 的点,每个点单独作为一个独立集。
对于度数 \(<\sqrt m\) 的点,设每个点所属的独立集编号为 \(t_i\)(从 \(1\) 开始),那么 \(t_i≤\sqrt m\) 。
于是独立集个数就是 \(O(\sqrt m)\) 的。
然后我们可以考虑快速找到两个集合 \(A,B\) 之间的边:
将 \(A\) 均匀分成两个集合 \(A1,A2\),\(B\) 均匀分成 \(B1,B2\),然后判断 \(A1∪B1,A2∪B1,A1∪B2,A2∪B2\),如果当前并集并非独立集,那么就递归下去求解。
显然,整个递归树的深度是 \(\log n\) 的,于是我们用 \(\log n\) 的代价找到了一条边,于是询问复杂度就是 \(O(m\log n)\) 的。
点击查看代码
CF1442D Sum
容易发现最终至多一个取了一部分的数组,其它要么完全取完,要么完全没有动过。
分治做背包,枚举是哪个物品只取了一部分,取最大值即可。
点击查看代码
CF1553H XOR and Distance
首先考虑一个真暴力,要求异或 \(x\) 之后的最小差,我们就建出原序列的 \(\text{Trie}\) 树,遍历整棵 \(\text{Trie}\)。对于每个分叉点(即,有两个儿子的点),我们在与 \(x\) 这一位相同的那一边查询异或最大值 \(mx\),不同的那一边查询异或最小值 \(mn\),再用 \(2^d+mn-mx\) 更新答案(\(d\) 是当前这条边在 \(\text{Trie}\) 上的深度)。
假如不对于每个 \(x\) 分别建 \(\text{Trie}\) ,从低位到高位枚举 \(x\) ,依次在原有 \(\text{Trie}\) 树上反转对应位的节点,\(\text{Trie}\) 树上深度为 \(d\) 的节点最多有 \(2^d\) 个,每个点有 \(2^{K-d}\) 次可能的询问,这样总复杂度为:
点击查看代码
CF343E Pumping Stations
注意到问题与任意两点在原图上的最小割相关,所以建出最小割树。
记 \(d(i, j)\) 表示节点 \(i,j\) 在最小割树上的简单路径经过的所有边的边权的最小值,问题转化为求一个 \(n\) 阶排列 \(p_1, p_2, \cdots, p_n\) ,最大化 \(f(p) = \sum\limits_{i = 1} ^ {n - 1} d(p_i, p_{i - 1})\) 。
由于 \(d(i, j)\) 是边权最小值的形式,所以我们猜测答案上界就是所有边的边权和。考虑构造。
找到整棵树上边权最小的边 \((u, v)\),设它把树分成 \(S, T\) 两个点集。
考虑最终的排列。如果 \(u\to v\) 这条边被经过超过一次,通过调整法容易证明不优,因此,我们断言必然存在最优排列使得 \(u\to v\) 只被经过一次,即必然是先完整地走完 \(S\),再从 \(S\) 中的某个点以 \(w(u\to v)\) 的贡献走到 \(T\) 中的某个点,再完整地走完 \(T\) 。
跨过 \(u, v\) 的这次移动 \(p_i\to p_{i + 1}\) 最小值已经是 \(w(u\to v)\) 了,所以无论 \(p_i\) 是 \(S\) 内部的哪个点,\(p_{i + 1}\) 是 \(T\) 内部的哪个点,都不会影响到 \(d(p_i, p_{i + 1})\) 。
这样,我们将问题划分成了在 \(S\) 和 \(T\) 内部的子问题,递归边界即点集内部只剩下一个点,此时直接输出它的编号即可。
时间复杂度是构建最小割树的复杂度,加上构造的复杂度 \(O(n^3m+n ^ 2)\) 。
点击查看代码
CF1179E Alesya and Discrete Math
考虑分治,每次将其分成两部分
左边:自变量取值范围 \([0,x]\) ,因变量取值范围 \([0,\frac{L}{2}]\) 。
右边:自变量取值范围 \([x,10^{18}]\) ,因变量取值范围 \([\frac{L}{2},L]\) 。
然后递归下去分治即可。
考虑如何求出 \(x\) ,对于所有的 \(f_i\) ,求出使得 \(f_i(x_i)=\frac{L}{2}\) 的 \(x_i\) 。因为函数取值单调不降,这里用一个二分查找即可,查询一次所需询问次数是 \(\log 10^{18}=60\) 次。(因为在 \(O\) 里带常数不太好,以下用 \(T\) 表示 \(\log 10^{18}\))。
然后可以找出 \(x\) 的中位数,分析一下这一部分的复杂度:
求出使得 \(f_i(x_i)=\frac{L}{2}\) 的 \(x_i\) 的复杂度是 \(O(T)\) ,递归 \(O(\log n)\) 层,每层对所有的 \(f_i\) 求 \(x_i\) 都需要 \(O(T)\) 。
总次数大概是 \(O(n\cdot T\cdot\log n)\approx 6\cdot 10^5\) 。
但是无法通过,我们需要进行优化,考虑 \(\text{kth_element}\) 的方法,随机选择一个函数,二分出它的 \(x\) ,再将其它函数与这个 \(x\) 比较,期望递归 \(\log\) 层,总操作次数 \(O(T\log n+n)\)。
下面分析时间复杂度:
设 \(n=2^s\) ,那么 \(i\) 层分治之后,段数是 \(2^i\) ,每段长度是 \(2^{s-i}\) 。
对于每段找中位函数所需的询问次数就是 \(O(T(s-i))\) 。
对于全部的寻找中位函数,总共需要
总复杂度是 \(O(n\log n+Tn)\) 。
点击查看代码