QOJ 杂题选做
#7943.LIS on Grid
约定网格左上角为 \((1,1)\),右下角为 \((n,m)\)。根据狄尔沃斯定理,我们设偏序关系为自己大于右上方的所有点,转化为求最小的链划分。不妨考虑二分答案,此处单调性显然,考虑 check 能否在满足每一列的黑格子限制的前提下构造出 \(k\) 条链,不难发现最大的限制其实是高度 \(m\),我们希望最大化每个格子的利用率,也就是将尽可能多的链留在下方。因此维护一个链的尾巴集合,每次到一个新链的时候就将每个尾巴向右移动一位。若 \(a_i\leq k\),此时一定合法,不再变化;否则我们需要把某些位置往上方拓展 \(a_i-k\) 个格子。不妨优先扩展最上方的一个尾巴,到顶后再考虑第二个......显然这是一个最优的方案,若不合法则不存在合法方案了。
#8079. Range Periodicity Query
首先可以利用 deque 将 \(S_n\) 生成出来,并求出 \(S_i\) 在该串中的对应区间。注意到 \(S_i\) 之间是包含关系,故对于一个长度 \(p\),其一定是一段前缀的 \(S\) 的周期。设 \(f_i\) 表示最大的 \(x\) 使得 \(S_x\) 有长度为 \(i\) 的周期。根据周期与 border 的关系,\(i\) 是一个字符串的周期的充要条件是 \(len-i\) 是这个字符串的一个 border 的长度,于是可以用哈希 \(O(1)\) 判定合法性,因此可以二分求出每一个 \(f\)。
求出 \(f\) 后,问题转为求出 \([l,r]\) 中最小的数 \(x\),使得 \(f_x\geq k\)。注意 \(f\) 是没有单调性的。考虑从大到小扫描 \(k\),将所有 \(f_x=k\) 的 \(x\) 加入到其对应的所有位置,将询问同时挂在 \(k\) 上,每次等价于询问区间最小值,使用线段树维护即可。
#5530. No Zero-Sum Subsegment
考虑前缀和数组,其要求为每个位置的值互不相同。不妨抽象成从 \(0\) 出发走到 \(s\),每次往两个方向中的某一个走 \(1\) 或 \(2\) 步,途中不能经过重复点的方案数。下面进行一些观察:
首先,折返只能发生两次,分别在初始时往负半轴走和最后超过 \(s\) 再折回来的情况,途中的路程是大致单向的。先考虑折返情况,我们从 \(0\) 出发,第一步往左跳,最后回到 \(1\) 的位置,用来错位的 \(1\) 可以往左也可以往右,故有以下两种可能组合:
- \(k\) 个 \(-2\),\(1\) 个 \(-1\),\(k+1\) 个 \(2\);
- \(k\) 个 \(-2\),\(1\) 个 \(1\),\(k\) 个 \(2\)。
此外在起点处可以不回头地走,共三种方案;终点处也有对称的三种方案。
对于中间的部分,我们需要解决在 \([l,r]\) 区间内走,\(l\to r\) 且超出区间的方案数。对于往回的步数,我们只能走成 \(2,-1,2\) 的路径,这等价于往右走 \(3\) 步。因此假设这个阶段需要用 \(i\) 个 \(2\),\(j\) 个 \(1\),\(k\) 个 \(-1\),\(0\) 个 \(-2\),则等价于走 \(k\) 个 \(3\),\(i-2k\) 个 \(2\),\(j\) 个 \(1\),可以利用组合数计算中间的方案数。
因此,对于两边的路径,我们直接枚举 \(9\) 种可能的组合,计算出每种组合对应花费的各个步数,再与中间部分的乘起来。注意到左右两侧的分配仅可能形如 \(k_1+k_2=D\) 的形式,无论如何分配,\(1,2,-1\) 的总量是确定的,因此只需分别考虑方案数再乘起来即可。
#8840. Lalo's Lawyer Lost
对于每一条边考虑覆盖次数。
对于不在环上的边,贡献次数可以达到左右两侧点数的较小值。在环上的边,需要进行整体考虑:把一个环抽出来,每个点上有权值,总权值和为 \(n\),给每个点匹配权值次,最大化最短距离和。这可以看做有一个 \(n\) 个点的环,边权为 \(0\) 或 \(1\),给每个点进行匹配,最大化最短距离和。结论是我们一定按照跨对角线方式匹配,通过调整并刻画覆盖边可以证明这一点。因此把一个环上的权值分成两个部分,然后双指针即可。
找环没必要建立圆方树,每个 dfs 树上的返祖边就对应一个环。
#1650. AND = OR
一开始的想法是,以一个值作为分界,大于等于 \(x\) 的分在与集合,小于 \(x\) 的分在或集合,但是划分位置太多不好维护。
考虑另一种划分:考察二进制下 \(1\) 的个数,个数大于 \(k\) 的分在与集合,小于 \(k\) 的分在或集合。此时,不能存在两个不同的值里 \(1\) 的个数等于 \(k\),否则不合法;根据等于 \(k\) 的值的个数可以分类讨论,求出 \(<k\),\(>k\) 部分的计算结果及值的个数,根据分在某同一侧和两侧都放进行简单讨论即可。
求值可以开 \(\log V\) 棵线段树,每棵树上存满足 \(popcount_x=k\) 的 \(x\) 的区间数量、区间或和区间与即可。总复杂度 \(O(n\log V\log n)\)。
#7250. Korn
考虑求欧拉回路的过程实际上是走出来任意一个回路后,遍历回路上的每个点,找到新环并合并,也就是说我们希望无论如何走,回路上都找不到新环。不难推出充要条件是所有环都经过起点。对每个被所有返祖边覆盖的点,忽略从其自身始发的返祖边,剩余返祖边的较深点的两两 LCA 都必须是自身。事实上判断最高和最深的两个点即可。
#6334. Passport
每个点拆成入点和出点,线段树优化建图。要求的是每个点到 \(1,n\) 的路径并的最小值,枚举分叉点 \(u\),有 \(ans_x=\min dis_{x,u}+dis_{u,1}+dis_{u,n}\),显然有不合法不优保证正确性。在反图上把后两项跑出来后,对每个起点求 \(ans\) 只需要以每个点为起点做多源最短路即可。
#3307. Query on a Tree 17
结论:树上较浅的带权重心是所有满足子树和严格大于二分之一的点中最深的一个。若有两个带权重心,则另一个一定是较浅的一个的所有儿子中,子树和恰为二分之一的一个。
经典做法是,找到 DFS 序上首个前缀和严格大于二分之一的点,则它一定在较浅带权重心的子树内。倍增即可判断。
#1089. Biological Software Utilities
树计数考虑 Prufer 和矩阵树,很遗憾的是关于完美匹配的判定需要知道每个点和深度有关的信息,然而上面两个工具都只和点的度数相关。考虑去掉完美匹配的部分,将两个完美匹配缩成一个点,考虑其构成的树的数量。设 \(n=2m\),则这样的树的数量为 \(m^{m-2}\)。对于每一条边,在两组完美匹配之间实际上都有四种可能的连边方式,故还有一个权值 \(4^{m-1}\)。
然后是把 \(n\) 个点两两分成 \(m\) 个无标号的组。先考虑若组之间有标号,答案为 \(\frac{n!}{2^m}\),原因是要除掉每一组内部的顺序。无标号再除掉 \(m!\) 即可。
#2881. Multithreaded Program
首先是这个流程难以刻画,其次正向贪心在有多个可能是终点的点时,正确性难以保证。考虑时光倒流,每次选择任意合法的即可。
#671. Shortest Path Queries
多次的最短路查询是困难的,一定要基于这个长条的形状做。注意到单源最短路更为容易,且在长上面,两个点中间的所有列都一定会经过。考虑一个类似 CDQ 分治的东西,借用线段树的分治结构,对于每一个可能的路径,都在恰好包含它的那个节点内的 \(mid\) 处统计答案(如果路径不过 \(mid\),则某个儿子才是恰好包含它的)。因此对于每个 \(mid\) 处的 \(W\) 个点分别跑该节点对应所有点的单源最短路。查询的时候,找到每一个完全包含询问区间的节点,枚举中间经过的是哪个点来统计答案即可。总复杂度 \(O(W^2H\log^2 H+qW\log H)\)。
当然也可以直接 CDQ,把所有询问离线后直接在每一层上跑一次即可,可以节省记录答案所用的空间。
#7932. AND-OR closure
对于每一个位 \(i\) ,考虑找到它在哪些数中为 \(1\),将这个集合记为 \(S_i\)。首先集合相同的位可以缩在一起;其次忽略掉 \(S\) 为空的位。我们考虑位之间的相互限制,有一个显然的事情是:若 \(S_i\subset S_j\),则若最终集合里某个数的第 \(i\) 位是 \(1\),则其第 \(j\) 位一定是 \(1\)。我们根据这样的限制连边 \(i\to j\),最终集合里的数的个数就是闭合子图的个数。
这里还需要补充的是,闭合子图代表的数一定可以被表示出来。考虑拿出度数为 \(0\) 的所有位,对于某个这样的位 \(i\),我们通过把 \(S_i\) 中的所有数与起来,即可得到 \(i\) 及 \(i\) 所有后继的位形成的集合。最后把所有度数为 \(0\) 对应的操作或起来,则得到了一个构造闭合子图对应数的方案。
考虑统计闭合子图个数,转为统计闭合子图中度数为 \(0\) 的点,它们形成一条反链。考虑 meet in the middle,分别处理 DAG 上靠后(为 \(1\) 的位数更多)和靠前二十个点的集合哪些合法,对前一部分做高维前缀和,后一部分在对应闭合子图的补集上统计答案即可。显然只会有靠前的对靠后的产生限制,靠后的不会对靠前的产生限制。
复杂度 \(O(n\log^2a+\sqrt a\log a)\)。
#3014. Cut it Out!
考虑环形区间 dp,设 \(f_{l,r}\) 表示 \(l\) 左侧、\(r\) 右侧的那条边已经被切开了,现在要切完 \([l,r]\) 内的最小代价,枚举下一步切谁即可 \(O(n^3)\) 完成转移。现在的问题是需要计算一条凸包内线段与凸包的交点、以及两条直线的交点。
第二个问题直接求是不难的。第一个问题可以预处理,枚举凸包的每一条边求交点。我们对于所有 \(x\) 小于线段中点的 \(x\) 坐标取 \(\max\),大于的取 \(\min\),即可找到两个交点,然后维护这两个交点到线段中点的距离即可。注意为了避免各种斜率为 \(\inf\)、斜率相等没有交点的问题,我们给每个点的坐标加一个 \(rand\times eps\) 的偏移量,其中 \(rand\in(0,1)\) 即可。
#9123. Kth Sum
一个暴力的做法是,二分答案 \(v\),枚举 \(a\) 的项,对 \(n^2\) 个 \(b,c\) 的组合利用双指针计数,复杂度 \(O(n^2\log n)\)。此处也可以改成对 \(b,c\) 做 \(n\) 次双指针,复杂度不变。
注意到总对数达到 \(10^{14}\) 级别,但询问只给到 \(10^9\),猜测可能和个数较小有关,尝试从这个角度进行优化。我们考虑优先做合法对数较多的 \(a\),即从小往大做,显然合法的 \((b,c)\) 逐步减少。考虑设定一个阈值 \(B\),设 \(x\) 表示枚举到 \(a_B\) 时的合法对数,则总对数小于 \(v\) 的必要条件是 \(Bx<v\),也即 \(x<\frac{v}{B}\)。因此,在 \(B\) 及之后的枚举中,最多只有较小的 \(\frac{k}{B}\) 个是有效的。通过多路归并不难求出这些和值。于是对于前 \(B\) 个 \(a\) 的值,每次跑 \(O(n)\) 的双指针。对于后面的值,我们不妨取出 \(\frac{k}{B}+1\) 个较小的值做 lower_bound,一旦发现最后一个值也合法,就直接判定大于等于。省略 lower_bound 的 log,总复杂度为 \(O(\frac{k}{B}\log n+nB\log n)\),取 \(B=\sqrt{\frac{k}{n}}\) 可以做到 \(O(\sqrt{nk}\log n)\)。

浙公网安备 33010602011771号