贪心构造DP 杂题选做Ⅲ

贪心构造DP 杂题选做Ⅲ,第1张

贪心/构造/DP 杂题选做Ⅲ

颓!颓!颓!(bushi

前传:

  • 贪心/构造/DP 杂题选做
  • 贪心/构造/DP 杂题选做Ⅱ
51. CF758E Broken Tree

讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的名字叫猛张(orz ztr),而我刚好在 11.4 把这题 A 了。


乍一看好像也没啥问题,不过模拟赛时间是 2020.11.3,而我 AC 这道题的时间是 2021.11.4(((

首先看到这样的题我们肯定会想到贪心,具体来说我们 DFS 一遍整棵树,DFS 到一个节点 \(x\) 时,我们考虑用最小的步数使 \(x\) 的子树不会断裂,那么我们就先遍历一遍 \(x\) 的子节点 \(u\),显然此时此刻 \(x\) 的所有儿子的子树都不会断裂了,但是 \(x\) 与 \(y\) 的边不一定,如果 \(y\) 子树内所有边的重量和大于此时此刻 \(x,y\) 之间的边的强度,那么我们就要减少 \(y\) 子树内的边的重量使 \(x,y\) 之间的边不会断裂。


显然,我们如果减少 \(y\) 子树内,深度最大的边的重量肯定是最优的,因此我们考虑每次取出 \(y\) 子树内的边中,下端点最深的边,那么这条边可以减少的重量可以写作 \(\min(w_e-1,p_e-sumw(t_e))\),其中 \(e\) 为边的编号,\(sumw(x)\) 表示 \(x\) 子树内所有边的重量和,\(t_e\) 为 \(e\) 这条边的下端点,求解 \(sumw(x)\) 可以使用树状数组做到 \(\log n\)。


直接做显然一条链就可以把其卡到 \(n^2\log n\),不过注意到如果一条边我们将它所有能减的重量都减掉了,那么由于我们是按深度贪心的,因此这条边子树内所有边都满足,我们已经把它们能减的重量都减掉了,因此这样的边肯定永无翻身之日,无法再减去更多的重量了,故此后我们肯定不会再使用这条边。


因此我们考虑对每个点维护一个堆 \(q_x\) 表示现在我们还没有被干掉的边的编号,然后每次取出队首元素以后查看我们是否必须将这条边能减的重量都减掉(即,目前 \(x\) 子树内所有边的重量和减去 \(y\) 与 \(x\) 的边的强度是否小于这条边能减的重量),如果是那么我们就将这条边 pop 出去并且永远不会再入队,否则我们就将这条边的重量及强度减去目前 \(x\) 子树内所有边的重量和减去 \(y\) 与 \(x\) 的边的强度再丢回队列里。


合并的时候就启发式合并两个堆即可,时间复杂度 \(n\log^2n\),可以使用左偏树做到 1log,不过由于我懒癌(我要被q毙了,fog)爆发就没有写。


52. CF356D Bags and Coins

首先考虑有解的充要条件是什么,可以发现,如果我们记最大的 \(a_i\) 为 \(mx\),那么 \(a_i=mx\) 的 \(i\) 必须是某棵树的根(如果有多个这样的 \(i\),那么必然至少有一个 \(i\) 是树根),因此有解的必要条件是存在 \(\{a_1,a_2,\cdots,a_n\}\) 的一个子集,满足子集中所有元素的和为 \(s\),且子集中至少有一个元素为 \(mx\)。


容易发现这也是充分条件——具体构造就是将那些不在子集中的元素按 \(a_i\) 从大到小排个序,然后依次挂在某个 \(a_i=mx\) 的 \(i\) 下面形成一条链即可。


于是问题转变为一个 01 背包问题,直接 01 背包显然不可取,不过注意到 \(dp\) 值每一位只有 \(0/1\) 两种可能,因此按照套路 bitset 优化一下,时间复杂度 \(\dfrac{ns}{\omega}\)。


这里有一个地方要稍微注意一下就是此题如何输出方案,我们设 \(fst_i\) 表示最早在加入 \(a_j\) 之后,\(i\) 可以被得到的 \(j\),转移大概就在执行 bitset 优化背包的套路语句 dp=dp|dp<<a[i] 之后,比较一下执行这个语句前后 \(dp\) 的对称差,设为 dif,然后用这题题解里提到的语句遍历一遍 dif 中所有 \(1\) 即可。


时间复杂度依旧是 \(\dfrac{ns}{\omega}\)。


53. CF797F Mice and Holes

观察到此题的一个性质:进入每个洞的老鼠,在将所有老鼠按坐标排序之后一定是一段连续的区间。


因此设 \(dp_{i,j}\) 表示前 \(i\) 个老鼠进入前 \(j\) 个洞的最小代价,转移就枚举第 \(j\) 个洞里进了多少个老鼠,设为 \(k\),那么有转移 \(dp_{i,j}\leftarrow dp_{i-k,j-1}+sum_{i,j}-sum_{i-k,j}\),其中 \(sum_{i,j}=\sum\limits_{k=1}^i|y_k-x_j|\),其中 \(x,y\) 分别表示老鼠和洞的坐标排好序后的结果,单调队列优化一波可以做到 \(\Theta(nm)\)。


54. CF1481F AB Tree

又是一道 nb tea……

首先看到这个设问,我们可以很自然地希望所有深度相同的点,我们给它们赋上的字母都相同,这样答案就可以达到理论下界 \(mxdep_1\),也就是所有点深度的最大值,这个非常好理解。


如果我们设 \(cnt_i\) 表示深度为 \(i\) 的点的数量,那么不难发现问题转化为一个 01 背包问题,可以像 52 题那样使用 bitset 优化,但由于此题数据范围扩大到了 \(10^5\),并且此题的背包具有一个很强的性质:\(\sum\limits_{i=1}^{mxdep_1}cnt_i=n\),故 \(cnt_i\) 中不同数的个数是 \(\Theta(\sqrt{n})\) 的,因此可以统计一下有多少个 \(cnt_i=j\),这样可以转化为多重背包问题,\(\Theta(n\sqrt{n})\) 求解。


接下来考虑更一般的情况,也就是 \(mxdep_1\) 的下界无法达到的情况。


可以证明答案的上界是 \(mxdep_1+1\),构造如下:我们考虑对每一层填数,对于第 \(i\) 层,我们考察第 \(i\) 层中的非叶节点,不妨设深度为 \(i\) 的点中有 \(c_1\) 个非叶节点和 \(c_2\) 个叶节点,那么我们先给 \(c_1\) 个非叶节点分配对应的字符,由于每个非叶节点都至少有一个儿子,因此非叶节点总数肯定 \(\le\) 剩余的 a,b 数量的一半,因此根据抽屉原理总存在一种字符满足其个数 \(\ge c_1\),我们给这些节点分配上这些字符即可,接下来考虑分配叶子节点,继续分情况,如果剩余的 a,b 个数都 \(\ge c_2\),那么我们直接给这些叶子节点也填上我们给非叶节点分配的字符,否则我们总可以用完一种字符,我们就把这种字符分给这些叶子节点,然后剩余节点全填上另一种字符即可,这样本质不同字符串个数不过 \(mxdep_1+1\)。


于是这题就做完了。


判一下 \(mxdep_1\) 的情况,对于 \(mxdep_1+1\) 的情况模拟一下上面的构造过程即可。


55. AT1999 [AGC002E] Candy Piles

AGC 时间到!我要 AGC!我要 AGC!A!G!C!A!G!C!(大雾

我们考虑将 \(a_i\) 从大到小排序并建一个表格,第 \(i\) 列有 \(a_i\) 个 \(1\times 1\) 的方格,那么可以发现,取糖果的过程可以视作一个以 \((1,1)\) 为起点的路径,其中将所有堆中的糖果个数减 \(1\) 可视作向上移动一步,取走糖果数量最多的堆可视作向右移动一步,那么一个取糖果的过程,就唯一对应一条 \((0,0)\) 到边界上的路径。


由于是博弈论,并且此题也没有很明显的涉及多个游戏要用 SG 定理什么的,因此考虑对每个状态标一下它的 P/N 态,边界上的点都是 P 态,对于一个非边界点,如果它上方和右方的点中有一个是 N 态那么它就是 P 态,否则它是 N 态,这样 \((0,0)\) 的状态就决定了答案。


直接一个个推显然不可取,不过注意到一个性质,那就是对于一条对角线而言,除了这条对角线上边界上的点,其余的点的状态肯定是相同的,因此我们考虑找到包含 \((0,0)\) 的最大正方形边长,设为 \(a\),那么 \((0,0)\) 的状态与 \((a-1,a-1)\) 状态相同,因此我们只需知道 \((a-1,a-1)\) 的状态,而显然如果 \((a-1,a-1)\) 到其上方和其右方的边界中,至少有一个是奇数,那么它就是 P 态,否则它是 N 态,这个直接求即可。


复杂度线性。


56. AT2044 [AGC004D] Teleporter

首先显然如果一组 \(\{a_i\}\) 符合条件,那么必然有 \(a_1=1\),因为我们如果建一张图并对所有 \(i\) 连边 \(i\to p_i\),那么我们肯定会得到一个基环内向树对吧,而如果这个内向树的环大小 \(\ge 2\),那么环上相邻两点传送 \(k\) 步后肯定位于不同的位置。


这样一来如果 \(a_1\ne 1\) 那么我们强制将 \(a_1\) 改为 \(1\) 并将答案加 \(1\) 即可,于是现在问题可以转化为,有一棵有根树,每次可以断掉一条边并加入一条新边,求最少多少次以后这棵树最大深度 \(\le k\)。


这是一个经典贪心模型,对于树上的贪心我们通常可以一遍 DFS 然后贪心地合并一些东西


此题也不例外,考虑一个点的命运:肯定是先顺着一路接上去,如果它的深度达到了 \(k\) 了就断开这个祖先与这个点所在这个祖先的子树之间的边,因此考虑直接维护这个贪心,我们设 mxdep[x] 表示目前 \(x\) 子树内的最大深度,如果 \(x\) 的一个儿子的 mxdep 达到了 \(k\) 就令答案加 \(1\),否则将 mxdep[x]mxdep[y]+1 取 \(\max\)。


时间复杂度线性。


然后我做这道题的时候脑抽了写了个堆的合并 2log?

57. CF1392G Omkar and Pies

首先发现对 \(s\) 作用 \(l,l+1,\cdots,r\) 的 *** 作,等价于对 \(s\) 作用 \(l,l+1,\cdots,n,n,n-1,\cdots,r+1\),这个可以由交换 *** 作的可逆性说明得到。


这样我们可将 *** 作写成两个后缀相减的形式,但直接将 \(l,r\) 独立开来还是有点困难。


不难发现,由于我们求 \(s,t\) 相同的字符数,因此我们可以反过来将 \(n\sim r\) 的 *** 作作用于 \(t\) 上,也就是说,对 \(s\) 进行 \(l,l+1,\cdots,n\) 的 *** 作,对 \(t\) 进行 \(r+1,r+2,\cdots,n\) 的 *** 作之后,\(s,t\) 相同的字符的数量,就等于对 \(s\) 依次进行 *** 作 \(l,l+1,l+2,\cdots,r\) 后 \(s,t\) 相同的字符数量。


我们预处理出 \(a_i\) 表示执行 \(i\sim n\) 的 *** 作后,\(s\) 会变成啥,\(b_i\) 也同理,那么题目可转化为,求出两个数 \(x,y\),满足 \(y-x\ge m\),且 \(a_x,b_y\) 的公共字符个数尽可能多。


注意到 \(a_x\) 中 \(1\) 的个数为定值,\(b_y\) 中 \(1\) 的个数也是定值,因此我们考虑设 \(c_1\) 表示 \(s\) 中 \(1\) 的个数,\(c_2\) 表示 \(t\) 中 \(1\)​ 的个数,再记 \(c\) 表示 \(a_x,b_y\) 中公共的 \(1\) 的个数,那么 \(a_x,b_y\) 相同的 \(1\) 的个数就可以用 \(c+(k-c_1)-(c_2-c)=k-c_1-c_2+2c\) 来表示,因此我们只用最大化 \(c\) 即可。


这个可以通过维护两个桶 \(mn_i\) 表示 \(i\subseteq a_x\) 的 \(x\) 的最小值,以及 \(mx_i\) 表示 \(i\subseteqq b_y\) 的 \(y\) 的最大值,然后枚举公共部分并做一个简单的判断即可。


时间复杂度 \(\Theta(mk+k·2^k)\)。


58. P6573 [BalticOI 2017] Toll

这……连线段树优化矩乘都能混到我这个 blog 里了?简直耸人听闻了(

一开始看错题了,以为边是双向边,后来才发现自己看错题了……

对于此题而言,如果图是个 DAG,并且连边的两点有性质 \(\lfloor\dfrac{a}{k}\rfloor=\lfloor\dfrac{b}{k}\rfloor-1\),因此我们可以直接将除以 \(k\) 下取整相同的 \(k\) 个数看作一个块,那么每条边相当于连接了相邻块的两个点,因此我们直接建一棵有块个数 \(-1\) 个叶节点的线段树,表示区间 \([l,r]\) 的节点处存着 \(a_{x,y}\) 表示从 \(lk+x\) 到 \(rk+y\) 最少需要多少代价,那么显然可以 \(k^3\) 合并,总复杂度 \(nk^3+ok^3\log n\)。


如果题目的边是双向边,那我们需要再预处理 \(d_{i,x,y}\) 表示 \(ik+x\) 与 \(ik+y\) 之间的最短距离,这个显然可以把它看作一张图后跑多源最短路求出,用 dijkstra 实现即可。


不难看出这张图点数是 \(nk\) 级别,边数是 \(nk^2\) 级别的,因此这部分预处理的复杂度为 \(nk^2\log n\),剩余部分都和 DAG 的部分类似,总复杂度 \(nk^3+nk^2\log n+nk^2\log n\)。


59. CF1601E Phys Ed Online

其实感觉在重大考试出纯贪心题是占少数,倒是有不少题是将贪心与计数/数据结构结合,这种数据结构/计数题一般是先给你一堆 *** 作,问你有多少个序列符合在多少多少次 *** 作之内达成什么目标/要动态维护一个集合之类的东西并查询最少进行多少次 *** 作才能打成什么目标之类的,而发现如何实现最优策略的过程,就需要贪心。


此题就是典型,虽然它的贪心异常简单

比赛现场先开 D 后开 E,巨大的失误。


首先一个非常显然的性质是我们肯定会恰好在 \(l,l+k,l+2k,\cdots\) 时刻用攒下来的入场券,这就要求我们在 \([l,l],[l,l+k],[l,l+2k],\cdots\) 时刻中各买一个入场券,而显然我们肯定会买这些区间中 \(a_i\) 最小的入场券,因此对于一组询问,它的答案可以表示为:

\[\sum\limits_{l+tk\le r,t\ge0}(\min\limits_{i=l}^{l+tk}a_i)
\]

考虑如何求之。


不难发现,询问的右端点其实不算太重要,因为对于使得 \(l+tk\le r\)​ 最大的 \(t\)​ 相同、左端点也相同的两个询问,它们的答案肯定是相同的。


而左端点就不同了,所有查询 \(\min\)​ 的区间的左端点都等于 \(l\)​,且区间长度都模 \(k\)​ 余 \(1\)​,这不禁启发我们将 \(l\bmod k\)​ 相同的询问放在一起处理。


我们将询问挂在 \(l\)​ 处然后枚举 \(l\bmod k\)​ 的值 \(i\)​ 并批量处理 \(i\equiv l\pmod{k}\)​ 的询问们。


当我们处理 \(i\equiv l\pmod{k}\)​ 的询问时,我们将 \(i\equiv j\pmod{j}\)​ 的点设为关键点,然后对于关键点之间的区间,我们提取出它们的最小值,这样我们可以得到一个长度大概是 \(\dfrac{2n}{k}\)​ 的序列,然后我们在这个序列上从后往前扫一遍单调栈,单调栈的同时处理出上相邻两个点 \(stk_{tp},stk_{tp-1}\)​ 之间有多少关键点 \(cnt\)​,并求出 \(a_{stk_{tp}}·cnt\) 的前缀和,这样查询时就在单调栈上二分离栈底最近的 \(\le l+\lfloor\dfrac{r-l}{k}\rfloor·k\) 的点,前面的段使用前缀和算出,最后一段单独处理一下即可做到 \(\Theta(\log n)\) 地查询。


总复杂度 \(\Theta((n+q)\log n)\)。


60. AT2304 [AGC010C] Cleaning

考虑找到一个度数大于 \(1\) 的点作为根进行一遍 DFS。


设 \(f_i\) 表示 \(i\) 子树内总共会向上延伸出多少条路径。


那么当我们 DFS 到一个点 \(x\) 时,考虑一个点的所有儿子延伸上去的路径的命运,要么两条路径合并成一条,要么继续向上延伸,我们假设 \(\sum\limits_{y\in\text{son}_x}f_y=sum\),那么假设有 \(t\) 对路径合并起来,显然就有 \(sum-2t\) 条路径向上延伸,而根据 \(t+sum-2t=a_x\) 可知 \(t=sum-a_x\),这样 \(f_x=2a_x-sum\)。


我们可以说明,如果有一个 \(f_x\notin[0,a_x]\),或者 \(\max\limits_{y\in\text{son}_u}f_y>a_x\),那么答案就是 NO,如果根节点的 \(f\) 值不为 \(0\),答案也是 NO


否则答案就是 YES


在上面的判定条件中,\(f_x\in[0,a_x]\) 是显然的,\(\max\limits_{y\in\text{son}_u}f_y\le a_x\) 的条件倒不算太显然,这里稍微证一下。


根据这里面第 \(9\) 题的经典结论,\(x\) 的儿子们可以两两匹配,当且仅当 \(\max\limits_{y\in\text{son}_u}f_y\le\dfrac{sum-f_x}{2}\),而根据 \(f_x=2a_x-sum\) 可知 \(\dfrac{sum-f_x}{2}=a_x\),因此 \(\max\limits_{y\in\text{son}_u}f_y\le a_x\) 是必要条件,证毕。


时间复杂度线性。


61. CF1329C Drazil Likes Heap

一道不算太难的贪心。


首先我们每次肯定会贪心地能删最大的就删最大的对吧,而每次最大的肯定存储在下标为 \(1\) 的位置对吧,因此我们考虑能 \(f(1)\) 就 \(f(1)\)。


那如果不能 \(f(1)\) 怎么办呢?那我们就继续尝试 \(f(2)\) 或 \(f(3)\) 呗,而我们肯定会贪心地先尝试 \(f\) \(a_2,a_3\) 中的较大者,即如果 \(a_2>a_3\),我们就先尝试 \(f(2)\),否则我们先尝试 \(f(3)\),如此进行下去即可。


受到这个思想的启发,我们考虑这样的过程:建一个堆维护现在可以尝试 \(f\)​ 的那些下标,每次取出这些下标中存储的键值最大的那个,并尝试 \(f\) 它,如果可行就算一次 *** 作结束了,否则把它d出堆并加入它的两个儿子,这样根据贪心的思想,可以使最终的和最小。


时间复杂度 \(\Theta(n\log n)\)。


注意每次数组清空到 \(2^{h+1}\),否则会获得 WA on test 66 的好成绩(貌似一车人现场因为这个 FST 了?)

62. CF1348E Phoenix and Berries

可以发现对于一棵树,我们最多只会填满一个只来自这棵树,且包含两种颜色的莓子的篮子。


因此考虑 \(dp_{i,j}\) 表示前 \(i\) 棵树,目前落单的红梅有 \(j\) 个,那么显然,目前落单的蓝莓有 \((\sum\limits_{t=1}^i(a_t+b_t)-j)\bmod k\),转移就枚举只用第 \(i\) 棵树上的莓子装下的篮子中,有多少个红梅,设为 \(l\),那么枚举 \(l\) 之后显然可以 \(\Theta(1)\) 转移,最终答案即为 \(\max\limits_{i=0}^{k-1}dp_{n,i}\)。


时间复杂度 \(\Theta(nk^2)\)。


63. CF1566F Points Movement

首先踢掉所有完全包含另一个区间的区间,以及已经符合要求(即,区间中存在一个点)的区间,显然如果其他区间都符合要求了,那这些区间一定符合要求了。


不难发现剩余的区间和点一定是一段区间,后面跟着一车点,再一段区间,再一车点,并且这些区间的左右端点一定都是单调递增的。


我们再来思考一下一个点的行动轨迹是什么样的,不难发现无非以下两种:先向左走一段然后掉头走到它原来的位置的左侧,或者先向右走一段然后掉头。


我们考虑以此为状态设计 DP。


设 \(dp_{i,0/1}\) 表示已经移动了前 \(i\) 个点,第 \(i\) 个点先向左走/先向右走的最小代价。


转移就套路地拆一下代价,将第 \(i\) 个点向左走的代价放在 \(dp_i\) 处计算,将走到原位置后向右走的代价放在 \(dp_{i+1}\) 处计算,然后枚举上一个点的状态转移即可。


时间复杂度 \(\Theta(n\log n)\)。


64. CF1442E Black, White and Grey Tree

首先可以发现所有同色连通块可以放在一起搞,因此可以干脆把它们缩成一个点来看待。


考虑只有黑白两种颜色时如何解决。


可以发现最优策略是每次删掉同色的叶子,然后在剩余的图中删掉另一种颜色的叶子,如此反复交替,手玩一下可以发现,如果我们建一张新图,对于有边相连的两点,如果两点颜色相同,则令它们之间的边的边权为 \(0\),否则令它们之间的边的边权为 \(1\),那么答案就是这张图直径的长度 \(d\) 除以 \(2\) 上取整加一,即 \(\lceil\dfrac{d}{2}\rceil+1\)。


接下来考虑有灰色的点的情况,那么我们的目标可以看作将灰色点替换为黑白之一,使得得到的图的直径长度尽可能小。


题解区貌似给出了一个线性的 DP 做法,但是我感觉这个做法可能有点问题,因此 yy 了一个正确一点的二分做法。


具体来说我们二分答案 \(mid\),然后设 \(dp_{i,0/1}\) 表示当 \(i\) 子树内的直径 \(\le mid\),且 \(i\) 的颜色为黑色/白色时,\(i\) 子树内离 \(i\) 最远的点离 \(i\) 距离的最小值,再设 \(mx_{i,0/1}\) 表示当 \(i\) 颜色为黑色/白色时,\(i\) 子树内经过 \(i\) 的路径长度的最大值的最小值。


那么加入一个子树 \(y\) 时显然有转移:

\[dp_{i,j}=\max(dp_{i,j},\min_{k}\{dp_{y,k}+[j\ne k]\})
\] \[mx_{i,j}=\max(mx_{i,j},\min_{k}\{dp_{y,k}+dp'_{i,j}+[j\ne k]\})
\]

其中 \(dp’_{i,j}\) 表示在更新 \(dp_{i,j}=\max(dp_{i,j},\min_{k}\{dp_{y,k}+[j\ne k]\})\) 前的 DP 值。


DP 完一个点 \(i\) 之后,如果 \(mx_{i,0}>mid\),则令 \(dp_{i,0}=\infty\),对于 \(dp_{i,1}\) 也同理,最后检验是否有 \(\min(dp_{i,0},dp_{i,1})\le mid\) 即可。


时间复杂度 \(\Theta(n\log n)\)。


65. CF1442C Graph Transpositions

首先注意到如果我们要进行的翻转 *** 作很多(\(\ge\log_2(n)\)),那肯定翻转 *** 作进行得越少越优。


因此我们考虑先设 \(dp_{i,j}\) 表示进行了 \(j\) 次翻转 *** 作,到达 \(i\) 最少需要多少代价。


其中 \(j\le\log_2(n)\),这样我们可以知道经过 \(\le\log_2(n)\) 次 *** 作最少需要多少代价可以到达 \(n\) 点,如果可以进行 \(\le\log_2(n)\) 次 *** 作到达 \(n\) 点那么我们直接输出进行 \(\le\log_2(n)\) *** 作到达 \(n\) 的最小代价即可,否则我们考虑以 \(1\) 为源点,将进行翻转 *** 作的次数为第一关键字,将进行的移动 *** 作的次数为第二关键字跑一遍最短路,同时记录下最短路取模后的值,然后输出 \(n\) 的距离即可。


66. CF1028H Make Square

本来以为是一道神仙数据结构题,后来发现其实是一道特别常规的数论题……

首先我们踢掉所有 \(a_i\)​ 的所有次数为偶数的质因子,对于出现次数为奇数的质因子我们令它的次数为 \(1\)​,设进行这样的 *** 作后得到的数列为 \(\{b_n\}\)​。


那么我们考虑将询问离线下来并挂在右端点处,然后从 \(1\)​ 到 \(n\)​ 扫一遍 \(b\)​ 序列所有元素,扫描过程中实时维护 \(pos_{i,j}\)​,表示满足 \(x\le\)​ 当前扫描到的位置,\(b_x\)​ 有 \(i\)​ 个质因子,\(j\mid b_x\)​ 的最大的 \(x\)​。


再设 \(mx_i\)​ 表示 \(f(b_x)+f(b_y)-2f(\gcd(b_x,b_y))(x<y)\) 的最大的 \(x\),其中 \(f(x)\) 表示 \(x\) 的质因子个数。


我们边扫描边维护这两个数组即可实现 \(\Theta(\omega(a_i))\) 求解每个询问的答案。


时间复杂度 \(n2^{\omega(a_i)}\omega(a_i)+q\omega(a_i)\)。


67. AT3878 [ARC089D] ColoringBalls

神仙题,题解

68. P7115 [NOIP2020] 移球游戏

没错就是那道现场把我送走的题,当时只会 0 分,现在会 70 分,巨大的进步(

首先我们考虑如果有两个长度为 \(m\) 的栈 \(x,y\),都由 \(0/1\) 组成,且它们当中 \(0\) 的个数的总和 \(>m\),以及空栈 \(n+1\),如何通过 \(x,y,n+1\) 将 \(x\) 全部变为 \(0\)​。


构造方案如下:

  1. 设 \(x\) 中有 \(cx\) 个 \(0\),那么我们将 \(y\) 中前 \(cx\) 个元素放入 \(n+1\)。


  2. 从上往下枚举 \(x\) 中的元素,如果是 \(0\) 则丢进 \(y\),否则丢进 \(n+1\)。


    此时 \(y,n+1\) 栈满,\(x\) 栈空。


  3. 将 \(y\) 的前 \(cx\) 个元素放入 \(x\),再将 \(n+1\) 的前 \(m-cx\) 个元素丢回 \(x\),\(n+1\) 的剩余 \(cx\) 个元素放回 \(y\)。


  4. 设此时 \(y\) 栈中有 \(cy\) 个 \(0\),那么我们将 \(x\) 中前 \(cy\) 个元素放入 \(n+1\)。


  5. 枚举 \(y\) 中所有元素,如果为 \(0\) 则放入 \(x\),否则放入 \(n+1\),此时 \(x,n+1\) 栈满,\(y\) 栈空,又显然 \(cx+cy\ge m\),故此时 \(x\) 栈中全是 \(0\)。


  6. 将 \(n+1\) 栈中所有元素放回 \(y\),以保证最终 \(n+1\) 栈还是空栈。


不难发现,在上述算法中我们的 *** 作次数上界为 \(7m\)。


我们称这个过程为“用 \(y\) 柱填充 \(x\) 柱的 \(0\)”,类似地我们也可定义“用 \(y\) 柱填充 \(x\) 柱的 \(1\)”。


接下来考虑如何用“用 \(y\) 柱填充 \(x\) 柱的 \(z\)”的基本 *** 作解题。


我们考虑分治,每次分治区间 \([L,R]\) 时记 \(mid=\lfloor\dfrac{L+R}{2}\rfloor\),然后我们将 \(\le mid\) 的元素记作 \(0\),\(>mid\) 的元素记作 \(1\),那么我们将 \(\le mid\) 的元素丢到左边,将 \(>mid\) 的元素丢到右边,具体方法是维护两个指针 \(l,r\),如果 \(l\) 栈与 \(r\) 栈中 \(0\) 的总数 \(\ge m\),那么我们就用 \(r\) 栈去填充 \(l\) 栈中的 \(0\),否则我们用 \(l\) 栈去填充 \(r\) 栈的 \(1\)。


不难发现这样 *** 作次数是 \(nm\log n\) 的,虽然有个 \(7\) 的常数,算上去大概是 \(8.4\times 10^5\),比 limit 略多了一丢丢,但由于卡不满,可以通过。


69. AT2046 [AGC004F] Namori

神仙题 %%%%%%%%%%

首先考虑树的情况,由于树是一个二分图,因此我们考虑将这棵树进行二分图染色并在所有黑点上放上一个标记,那么每次 *** 作可以视作,每次选择一个端点标记是一黑一白的边,并将它们的标记交换,要将原来有标记的位置都变得没有标记,原来没有标记的位置都变得有标记,最少需要多少步。


因此显然如果给树二分图染色后,黑点个数与白点个数不相等,答案就是 \(-1\)​,否则我们不妨以 \(1\)​ 为根 DFS 一遍整棵树,那么对于一棵子树 \(x\)​,设子树中黑点个数为 \(B\)​,白点个数为 \(W\)​,那么显然 \(x\)​ 与其父亲交换次数的下界就是 \(|W-B|\)​,而我们也不难达到这个下界:从叶子开始贪心,每次先复原每个叶子的子树,如果要交换就交换,这样我们就可以使 *** 作次数达到下界 \(\sum\limits_{i=1}^n|W_i-B_i|\)​,其中 \(W_i\)​ 表示 \(i\) 子树内白点个数,\(B_i\) 表示 \(i\) 子树内黑点个数,这样我们就完美地解决了树的情况。


接下来考虑基环树的情况。


解决树的情况的过程告诉我们,从二分图染色的角度解决这道题可能会比较妙,因此考虑将基环树也进行二分图染色——但是对于基环树而言,不太一样的一点是不一定存在合法的染色方案。


因此我们需要再将基环树的情况分为奇环和偶环分别处理。


对于偶环的情况,我们不妨 fix 偶环上一条边,然后设这条边将 \(x\) 个黑点传输到上面去(其中 \(x\) 可以为负数,\(x\) 为负数的情况则意味着这条边将 \(-x\) 个黑点传输到下面)。


那么我们把这条边从基环树中删去再做一遍 DFS,这样一来每个点子树内黑点与白点之差(带符号)就可以用一个代数式 \(c_i+k_ix(k_i\in\{1,-1\})\) 表示,其中 \(c_i\) 为常数,可以通过对删掉这条边后剩余的树做一遍 DFS 求得。


这样一来问题的答案就可写作 \(\min_{x}\sum\limits_{i=1}^n|c_i+k_ix|\),这是一个经典初一数学问题,直接取所有零点的中位数即可。


对于奇环的情况,我们也 fix 环上的一条边 \(e\),那么我们倘若对剩余的树跑一遍黑白染色,得到的图中,\(e\) 的两个端点颜色必然不同,这样每次 *** 作 \(e\),都会使黑点个数 \(-2\),由于最终得到的图中,黑点和白点个数应当相同,我们可以知道我们 *** 作了多少次 \(e\) 这条边,这样我们把这条边删掉后再跑一遍树的情况,这样可以算出答案。


时间复杂度线性。


70. AT2166 [AGC006E] Rotate 3x3

首先每一列的三个数肯定是连续的三个数 \(3k+1,3k+2,3k+3\),并且 \(3k+2\) 肯定在中间,这个直接判掉即可。


判掉之后我们不妨设 \(p_i=\dfrac{a_{2,i}+1}{3},rv_i=[a_{1,i}>a_{3,i}]\)。


那么问题可以转化为,初始有一个排列 \(p’\) 满足 \(p’_i=i\),以及一个值域为 \(\{0,1\}\) 的数组 \(rv’\),初始 \(rv’_i=0\)。


每次可以选择一个下标 \(i\in[1,n-2]\),并交换 \(p’_i,p’_{i+2}\),交换 \(rv’_i,rv’_{i+2}\) 并将 \(rv’_i,rv’_{i+1},rv’_{i+2}\) 全部异或上 \(1\)。


问是否能够使最终 \(p=p’,rv=rv’\)。


考虑如何判定它是否有解。


首先奇数位上的数换来换去都只能留在奇数位,因此如果有一个奇数 \(i\) 满足 \(p_i\) 为偶数,或者一个偶数 \(i\) 满足 \(p_i\)​ 为奇数,那肯定就无解了。


那还有没有必要条件呢?注意到如果我们对某个奇数 \(i\) 执行上述 *** 作,那么奇数位上的逆序对个数的奇偶性会发生改变,同时偶数位上的 \(rv\) 的异或值也会改变,因此一个局面符合要求的必要条件还有偶数位上 \(rv\) 的异或和与奇数位上逆序对个数的奇偶性相同,奇数位上 \(rv\) 的异或和与偶数位上逆序对个数的奇偶性也相同。


这个树状数组求一下即可。


加上这两个条件之后是否充分了呢?写个程序 check 一下就会发现它确实充分了,虽然大概我也不太会证,不过既然 AC 了你为啥还要管它呢(大雾

时间复杂度 \(\Theta(n\log n)\)。


71. AT2170 [AGC007C] Pushing Balls

一道非常让人谔谔的打表找规律题,虽然我现在也不太懂它为什么会有这个规律(

通过打 \(n=3\)​​ 的表可以发现,经过一次 *** 作之后,剩余的坑之间的期望距离也是成等差数列的,具体来说,假设一开始有 \(n+1\)​ 个洞,前两个洞初始距离为 \(d\),从第三个洞开始,每个洞与前一个洞的距离,都等于前一个洞与再前一个洞的距离 \(+x\)。


那么经过一次 *** 作以后:

  • 前两个洞的距离的期望值 \(d’\)​ 为 \(d+\dfrac{2d+5x}{2n}\)
  • 从第三个洞开始,每个洞与前一个洞之间的距离的增量的期望值 \(x’=x+\dfrac{4d}{2n}\)
  • 这一次推球期望的移动距离为 \(d+\dfrac{2n-1}{2x}\)。


如此递推下去即可。


时间复杂度 \(\Theta(n)\)。


72. AT2172 [AGC007E] Shik and Travel

首先看到这种最大值最小的问题,一眼二分答案。


考虑如何 check 一个答案 \(mid\) 是否合法,我们设 \(dp_{x,a,b}\) 表示 \(x\) 子树内,\(x\) 第一个到达的叶子离 \(x\) 的距离为 \(a\),最后一个到达的叶子离 \(x\) 的距离为 \(b\) 是否可行,转移就设 \(ls,rs\) 分别为 \(x\) 的两个儿子,那么 \(dp_{x,a,b}=(\operatorname{or}\limits_{c+d\le mid}dp_{ls,a,c}\land dp_{rs,d,b})\lor (\operatorname{or}\limits_{c+d\le mid}dp_{rs,a,c}\land dp_{ls,d,b})\)。


这样直接转移显然复杂度过高。


不过注意到如果两个状态 \(dp_{x,a,b}=dp_{x,c,d}=1\) 且 \(c\ge a,d\ge b\)​,那么这样的状态是没有用的,因此我们考虑对每个 \(x\) 开个 vector<pair<int, int> > 记录一下它所有有用的状态,转移时就在两边的 vector 里 two pointers 一下找到有用的状态后 sort 一下把所有无用状态去掉即可。


时间复杂度 \(n\log n\log v\)。


73. Atcoder Regular Contest 108 F Paint Tree

万年一遇水 ARC F(大雾

首先做题做多一点的同学看到这样的设问可以立马反应过来,距离最远的两个同色点中,肯定至少有一个是直径的一个端点,这里稍微证一下:

  • 如果直径两个端点颜色相同,那么显然距离最远的两个同色点就是直径的端点。


  • 否则直径的两个端点颜色不同。


    这一步我们考虑反证法,假设同色点之间距离最远的两点 \(u,v\) 都不是直径的端点,直径的两个端点为 \(U,V\),那么我们考虑找出 \(U,V\) 中与 \(u,v\) 颜色均相同的点,不妨设其为 \(U\)。


    我们继续分情况讨论:

    • 如果 \(u,v\) 间的路径与 \(U,V\) 间的路径的交集为空,那么我们考虑将 \(U,V\) 之间的链拉成一长条排成一排并假设 \(u,v\) 两个点均挂在 \(x\) 的子树内,再假设 \(u,v\) 的 LCA 为 \(l\),那么显然 \(u\) 到 \(l\) 的距离 \(\le\) \(U\) 到 \(x\) 的距离,否则 \(u,V\) 就成了新的直径的两个端点了,因此我们完全可以把 \(v\to l\) 这一段替换为 \(U\to x\) 这一段。


      这样 \(u,U\) 两点颜色相同并且它们间的距离 \(\ge u,v\) 两点间的距离,这样我们就调整得到了一个以直径端点为端点,且长度更长的路径。


    • 如果 \(u,v\) 间的路径与 \(U,V\) 间的路径的交集不为空,那么假设 \(u,v\) 间的路径与 \(U,V\) 间的路径的交集为 \(x\) 到 \(y\) 之间的路径,且 \(x\) 比 \(y\) 更靠近 \(U\),那么我们考虑 \(v\) 到 \(U\) 之间的路径,显然 \(u\) 到 \(x\) 的距离 \(\le U\) 到 \(x\) 的距离,否则 \(u,V\) 就成了新的直径的两个端点了,又由于 \(x\) 到 \(v\) 之间的路径为两个路径的公共部分,因此 \(U\) 到 \(v\) 之间的距离 \(\ge u\) 到 \(v\) 之间的距离,我们也调整得到了一个以直径端点为端点,且长度更长的路径。


这样解法就很明显了:求出直径的两个端点以及每个点到直径的两个端点间的距离,然后将每个点到直径的两个端点间的距离放到一个 vector 里并从大到小排序,然后枚举这个最长距离是什么,然后在遍枚举时边算个方案数即可。


时间复杂度 \(\Theta(n\log n)\)。


74. CF1027F Session in BSU

NOIp 前刷道不算太难的题调整一下自爆的心态。


感觉 NOIp 要退役了/kk

首先先离散化。


显然答案具有单调性,因此考虑二分答案 \(mid\)。


考虑如何 check。


这个“每天最多考一次试”的条件让我们不禁想到二分图匹配,因此考虑建一张二分图,将考试放在左边,日期放在右边。


对于每个 \(i\),如果 \(a_i\le mid\),则从左部第 \(i\) 个点向右部第 \(a_i\) 个点连边,对于 \(b_i\) 也同理,检查得到的二分图是否存在完美匹配(即大小为左部点个数的匹配)即可。


直接流肯定会 TLE。


注意到这张图的特殊性:每个左部点的度都 \(\le 2\)。


因此考虑用于解决二分图完美匹配的利器:Hall 定理。


运用 Hall 定理可知,题目等价于求对于每个左部点的集合 \(S\),是否都有 \(|\text{Nb}(S)|\ge |S|\),其中 \(\text{Nb}(S)\) 表示 \(S\) 中点的邻居组成的集合。


而根据“每个左部点的度都 \(\le 2\)”的性质,如果我们选了一个右部点,那么我们把所有与这个右部点相连的左部点选上,肯定会使左部点个数 \(-\) 与这些左部点相连的右部点个数不减,如此递归下去显然可以选到每个连通块。


因此我们只需检验最有可能不合法的左部点的集合,也就是每个连通块中左部点的集合是否符合要求即可,这个可以并查集维护,时间复杂度 \(\Theta(n\log n\alpha(n))\),擦时限过题/cy

75. AT4512 [AGC030C] Coloring Torus

NOIp 前最后一道题,到这个点了就只能祈祷 NOIp 碰到类似的题能够做得比较顺利了/kel

首先我们有一个非常显然的构造方法,那就是构造一个 \(k\times k\) 的方阵满足第 \(i\) 行的元素全是 \(i\)​。


但是由于 \(k\le 1000\),而我们要求构造出的矩阵大小 \(\le 500\),因此对于 \(k>500\) 的情况,直接这么构造是不可取的,只能考虑换个构造方法。


不难发现,如果我们令 \(a_{i,j}=(i+j-1)\bmod n+1\),那么构造出来的矩阵中,任意一点 \((i,j)\) 的相邻两个元素必定是两个 \((i+j-2)\bmod n+1\) 和两个 \((i+j)\bmod n+1\),因此这个矩阵必定满足条件,譬如当 \(n=6\) 时构造出的矩阵如下所示:

2 3 4 5 6 1
3 4 5 6 1 2
4 5 6 1 2 3
5 6 1 2 3 4
6 1 2 3 4 5
1 2 3 4 5 6

但是这样还是不符合 \(k\) 的限制。


怎么办呢?可以发现,对于每两条 \(\bmod n\) 相同的对角线,我们并不一定要在它上面填同一元素,譬如我们可以将两个填了 \(3\) 的对角线上嵌上 \(7\),这样可以得到如下所示的矩阵:

2 3 4 5 6 1
7 4 5 6 1 2
4 5 6 1 2 3
5 6 1 2 7 4
6 1 2 3 4 5
1 2 7 4 5 6

显然这样构造仍然合法。


受到这个思想的启发,我们考虑这样应对 \(k>500\) 的情况:首先我们构造一个 \(500\times 500\) 的方阵 \(a\),满足 \(a_{i,j}=(i+j-1)\bmod 500+1\),然后我们遍历每一个对角线,如果这个对角线上填的数 \(\le k-500\),那么我们考虑从左往右遍历这个对角线,如果这个对角线上的点 \((i,j)\) 满足 \(i+j\le 500\),或者 \(i+j\)​ 为奇数,那么我们就依次将这个对角线上第 \(1,3,5,\cdots,2t+1(t\in\mathbb{Z})\) 个点加上 \(500\),否则我们就给对角线上第 \(2,4,6,\cdots,2t(t\in\mathbb{Z})\) 个点加上 \(500\)。


手玩一下可知这样构造的正确性。


时间复杂度 \(\Theta(k^2)\)。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/589352.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存