NOIp 前夜了,可我还是发现自己有一车 blog 没补,所以只好开一个新坑/wul
前传:
76. CF1539E Game with Cards
考虑设 \(dp_{i,0/1}\) 表示目前已经进行了前 \(i\) 次操作,第 \(i\) 次操作替换了左手/右手是否可行,以 \(dp_{i,0}\) 为例,转移就枚举上一次使用右手是拿一次操作,不妨称之为 \(j\),那么有转移 \(dp_{i,0}\leftarrow dp_{j,1}\land[a_{l,j+1}\le k_{j+1}\le b_{l,j+1}]\land[a_{l,j+2}\le k_{j+2}\le b_{l,j+2}]\land\cdots\land[a_{l,i-1}\le k_{i-1}\le b_{l,i-1}]\land[a_{r,j+1}\le k_j\le b_{r,j+1}]\land\cdots\land[a_{r,i-1}\le k_j\le b_{r,i-1}]\)。直接做是三方的,显然不可取,因此考虑预处理一些东西。
我们预处理出 \(nxt_{i,0}\) 表示最大的 \(r\),满足 \(\forall j\in[i+1,r]\) 都有 \(a_{l,j}\le k_i\le b_{l,j}\),同理设 \(nxt_{i,1}\) 表示最大的 \(r\),满足 \(\forall j\in[i+1,r]\) 都有 \(a_{r,j}\le k_i\le b_{r,j}\)。
我们再设 \(pre_{i,0}\) 表示最小的 \(l\),满足 \(\forall j\in[l,i]\) 都有 \(a_{l,j}\le k_j\le b_{l,j}\),以及 \(pre_{i,1}\) 表示最小的 \(l\),满足 \(\forall j\in[l,i]\) 都有 \(a_{r,j}\le k_j\le b_{r,j}\),
那么 \(dp_{j,1}\) 可以转移到 \(dp_{i,0}\) 的充要条件是 \(dp_{j,1}=1\),且 \(nxt_{j,1}\ge i,pre_{i,0}\ge j\)。因此我们考虑建两棵树状数组 \(T_0,T_1\),对于一个 \(dp_{i,0}=1\) 的 \(i\),我们就令 \(T_0\) 中 \(nxt_{i,0}\) 的上位置对 \(i\) 取 \(\max\),对 \(dp_{i,1}\) 也进行同样的操作,那么 \(dp_{i,0}=1\),等价于树状数组 \(T_1\) 上 \([i,n]\) 的后缀 \(\max\) \(\ge i\),\(dp_{i,1}=1\) 的条件也是类似的,这个在树状数组查一遍后缀 \(\max\) 即可转移。
至于输出路径,就随便记录一个 \(pre_{i,0/1}\) 表示 \(dp_{i,0/1}\) 是从哪儿转移来的,然后最后不停地跳 pre
即可。
时间复杂度 \(\Theta(n\log n)\)。
77. AT2667 [AGC017D] Game on Tree
打 CF GR 时发现 I 题题面里有一道我没做过的 AGC 就在弃赛以后来做了(
首先先抛结论:考虑 SG 定理,那么每个子树的 SG 值等于其所有儿子的子树的 SG 值加 \(1\) 的异或和。
为什么呢?考虑每次删除一个子树 \(x\) 内的边的过程是怎么样的,我们假设 \(x\) 有 \(t\) 个儿子,那么我们将 \(x\) 复制 \(t\) 边,然后每个 \(x\) 下面都接上 \(x\) 的一个儿子的子树。那么显然这 \(t\) 棵树可以视作独立的游戏,直接将它们的 SG 值异或起来就是原游戏的 SG 值。那么又该如何算根节点只有一个儿子的游戏的异或值呢?可以证明,如果根节点只有一个儿子的情况,那么它的 SG 值就等于它唯一的儿子的子树的 SG 值加 \(1\),这个就考虑,如果我们割掉了 \(x\) 与这个儿子之间的边,那么只剩下一个节点,SG 值显然为 \(0\),而如果第一次割掉的边不是 \(x\) 与其儿子的边,那么我们归纳一下可以得到剩下部分的 SG 值就等于去掉根节点后剩余部分的 SG 值加一。换句话说,对于割掉 \(x\) 的儿子的子树内的边可以得到的 SG 值 \(x\),\(x+1\) 同样可以被得到,反之对于对于割掉 \(x\) 的儿子的子树内的边后不可以得到的 SG 值 \(x(x\ge 0)\),\(x+1\) 同样不可以得到,这样 \(x\) 的子树的 SG 值就显然等于其儿子的 SG 加一。
78. CF1610I Mashtali vs AtCoder
关于上题中提到的 GLBR 的 I 题,它来了(
首先套用上一题的结论解决 \(k=1\) 的情况:一棵子树的 SG 值等于其儿子的 SG 值 \(+1\) 的异或和。
对于 \(k>1\) 的情况,有这样的结论:我们将编号为 \(1,2,3,\cdots,k\) 的点拎出来建一棵虚树并缩成一个点,不妨令这个点为根节点,然后将所有在缩点后,一个端点在缩成的连通块,另一个端点不在的边全部接到根节点上,那么 \(k\) 时的 SG 值,就等于以缩点之后的点为根计算出它们的 SG 值后,根节点的 SG 值,异或上 \(1\sim k\) 的虚树中的边数 \(\bmod 2\),只不过在计算根节点的 SG 值时,直接将根节点的儿子的 SG 值异或起来即可,不用 \(+1\)。
这里稍微胡半个证明:首先我们称连接两个都在虚树中的边的点为一类边,其余的边为二类边,那么我们将割掉的边分为一类边和二类边处理,如果我们割掉一条一类边,那么根据 SG 值的定义,这条边所在缩点之后根节点的子树的 SG 值肯定会发生变化,而如果我们割掉一条二类边,那么二类边的奇偶性就会变化,因此不论割掉什么边,游戏的 SG 值总会发生变化。
为什么说是半个证明呢?因为我不太会证为什么一种局面总可以到达 SG 值比它小的局面(
因此对于本题而言,我们可以直接向上面那样加入一个点时不断跳 father 并将路上经过的边标记为二类边,由于每条边最多被标记一次,因此总复杂度 \(\Theta(n)\)。
79. CF1612F Armor and Weapons
首先关键性质:答案不超过 \(\dfrac{\max(n,m)}{\min(n,m)}+40\)。
因此不妨假设 \(dp_{i,j}\) 表示目前武力值最高的盾的武力值为 \(i\),进行了 \(j\) 次操作,所能够得到武力值最大的武器,转移就分下一次买盾和买武器处理即可。
时间复杂度 \(40n\log n\),瓶颈在于判断一对 \((i,j)\) 是否在读入的 \(q\) 组二元组中出现过。
80. CF1338D Nested Rubber Bands
一道看似很无从下手的题。不过仔细分析一下还是挺有迹可循的(
首先碰到这样的问题我们肯定要考虑什么样的序列可能符合条件。分析一下能够得到,一种选择符合条件,当且仅当对于所有点 \(u\),都不存在三个邻居 \(x,y,z\),满足去掉 \(u\) 后三个点所在的连通块中,都除了 \(x/y/z\) 之外还选择了其他的点,这是因为假设 \(x\) 所在的连通块中选择了 \(a(a\ne x)\),\(y\) 所在的连通块中选择了 \(b(b\ne y)\),\(z\) 所在的连通块中选择了 \(c(c\ne z)\)。且方便起见假设 \(c\) 包含于 \(b\),\(b\) 包含于 \(a\),那么画出图来肯定是张这样的:
而我们希望 \(u\) 与 \(x,z\) 相交而与 \(b\) 不相交,显然在上图中这无法办到。
直接用这个结论解题貌似有点难以下手,我们不妨对这个结论进行等价转换。可以发现一种等价的表述:对于每一种合法的方案,必然存在一条路径 \(u,v\),满足所有选择的点到这条路径距离 \(\le 1\),也就是说题目等价于选择一条路径 \(u,v\),并将所有到这条路径距离 \(\le 1\) 的点提取出来求出它们的最大独立集。直接做显然会 TLE,考虑 \(dp\) 的思想,设 \(dp_{i,0/1}\) 表示目前考虑到 \(i\),\(i\) 是链的一个端点并且 \(i\) 选了 / 没被选所能选择的最大的点数。考虑转移,假设我们目前 DFS 到点 \(x\),下面要加入 \(x\) 的一个儿子 \(y\),那么有转移:
直接转移即可。时间复杂度线性。
81. AT4518 [AGC032C] Three Circuits
不难发现,一个连通块是一个题目中所谓的“可以经过重复点的环”,当且仅当它存在欧拉回路,即它连通并且每个点的度都是偶数。
那么我们的任务就可以转化为,将连通块的边集分成三部分 \(A,B,C\),满足它们都有欧拉回路。一个显然的必要条件是每个点在原图中的度都是偶数,否则假设 \(x\) 在原图中的度是奇数,那么在 \(A,B,C\) 中,至少有一部分满足 \(x\) 的度是奇数,不合题意。但是每个点的度都是偶数的情况也不一定符合条件,譬如一个环的情况就无法拆成符合条件的三个子图,因此考虑进一步分类讨论:
-
如果存在一个点 \(x\) 的度 \(\ge 6\),那么我们感性地理解一下,每次选择这个点的两条出边,然后顺着找出经过这两条出边的一个环,然后将这个环从这张图中删去,如果删去这个环之后图被分成了两个连通块,那么我们就将不包含 \(x\) 的部分与之前拆出来的那个环归到同一个边集中。如此操作两次,连带剩余的部分,刚好三个回路。
-
如果所有点度都 \(\le 2\),那么原图是一个环,显然无法完成任务。
-
如果度数最大的点的度数恰好等于 \(4\),这部分有点繁琐,我们进一步分类讨论:
-
如果度数为 \(4\) 的点只有一个,那么任务也没法完成,输出
No
。 -
如果度数为 \(4\) 的点的个数 \(\ge 3\),那么画个图感性理解一下总是有解的,直接输出
Yes
即可。 -
如果度数为 \(4\) 的点的个数恰好等于 \(2\),那么再手玩一下可以发现这种情况的图可以被分为两大阵营,一类如下图左边所示,这种情况下原图无法拆成三个环;一类如下图右边所示,这种情况下原图可以被拆成三个环。那么我们如何区分这两类呢?我们找出原图中两个四度点 \(A,B\),稍微分析一下可以发现,一张图属于右边那个阵营,当且仅当 \(A\) 的所有邻居 \(x\) 中,满足 \(x\) 能够不经过 \(A\) 到达 \(B\) 的点数 \(\le 2\),这个直接枚举一下然后 DFS 一遍即可。
-
时间复杂度线性。
82. P5362 [SDOI2019]连续子序列
首先思考什么样的序列 \(S\) 能够成为 T.M 序列的子序列。我们发现这个 T.M. 序列的定义有点像一个二叉树的结构,具体来说 T.M 序列可以通过如下方式得到:首先写上一个 \(0\),然后建立一棵以 \(1\) 节点为根无限延伸的满二叉树,\(1\) 号节点的权值为 \(1\),对于每个节点,如果它的权值是 \(0\),那么它的左儿子权值为 \(0\),右儿子权值为 \(1\),否则它的左儿子权值为 \(1\),右儿子权值为 \(0\)。然后将每一层的数字按顺序写下来即可得到完整的 T.M. 序列。
不难发现上面的过程可以用“长”的过程来类比,受到上面的思想的启发,我们不妨也来考虑 \(S\) 是从什么序列 \(T\) 长出来的,对于一个序列 \(S\),分情况讨论:
- 如果 \(|S|\) 为奇数,那么有两种可能的长法:
- 一是将 \(S\) 中字符按 \(S_{1},S_{2}\) 配对,\(S_3,S_4\) 配对,\(\cdots\),\(S_{|S|-2},S_{|S|-1}\) 配对,如果配对的两个字符是 \(01\) 则在 \(T\) 末尾插入一个 \(0\),否则如果是 \(10\) 则插入一个 \(1\),否则则说明不可能是通过这种方式长出来的,最后落单的元素 \(S_{|S|}\) 就直接加入 \(T\) 末尾即可。
- 另一种是将 \(S\) 中字符按 \(S_{2},S_{3}\) 配对,\(S_4,S_5\) 配对,\(\cdots\),\(S_{|S|-1},S_{|S|}\) 配对,然后按照上一种情况的方式往 \(T\) 里面插入元素。这样开头会有一个落单的元素,在 \(T\) 的开头预先插入一个 \(S_1\oplus 1\) 即可。
- 如果 \(|S|\) 为偶数,那么也有两种可能的长法:
- 一是将 \(S\) 中字符按 \(S_{1},S_{2}\) 配对,\(S_3,S_4\) 配对,\(\cdots\),\(S_{|S|-1},S_{|S|}\) 配对的方式插入字符。
- 还有一种方式是将 \(S\) 中字符按 \(S_2,S_3\) 配对,\(S_4,S_5\) 配对,\(\cdots\),\(S_{|S|-2},S_{|S|-1}\) 配对。这样 \(S_1\) 和 \(S_{|S|}\) 均会落单,这可以通过把 \(S_1\oplus 1\) 插到 \(T\) 的开头,\(S_{|S|}\) 插到 \(T\) 的结尾。
可以证明,如果 \(|S|>3\),那么对于任意一个是 T.M. 序列的子序列,总存在唯一的拆分方式,因为对于 T.M 序列中任意一个长度 \(\ge 4\) 的连续段,总存在相邻且相同的字符。这就导致恰好一种拆分方式不合法,因此对于 \(|S|\le 3\) 特判一下,否则如果 \(T\) 符合要求,那么 \(S\) 也符合要求,递归一下即可,时间复杂度 \(\Theta(\sum\limits_{k}\lfloor\dfrac{|S|}{2^k}\rfloor)=\Theta(|S|)\)。即我们实现了在 \(\Theta(|S|)\) 的时间内判定一个字符串是否是 T.M. 序列的子序列。
接下来考虑如何计算答案。我们设 \(f(S,k)\) 表示往 \(S\) 后面添 \(k\) 个字符后能够得到多少 T.M. 序列的子序列,如果 \(|S|+k\le 3\),那么特判一下即可得到,否则根据上面的结论,我们枚举得到的字符串是由哪种拆分得到的,这样我们可以得到 \(S\) 对应的序列 \(T\)。进而得到新的 \(k\),继续递归计算即可,时间复杂度 \(T(|S|+\log_2(k))\)。
83. CF360E Levko and Game
思维题杀我/dk
不难发现对于每一条权值自定的边,如果它的权值既不是 \(l_i\) 也不是 \(r_i\),那么我们将其调整为 \(l_i\) 或 \(r_i\) 肯定不会影响答案,因为如果它被先手经过没被后手经过,那么我们将它调整为 \(l_i\) 肯定更优;如果它被后手经过而没被先手经过,那么我们将它调整为 \(r_i\) 肯定最优。而如果它既被先手经过也没被后手经过,那不论将其调整为 \(l_i\) 还是 \(r_i\),得到的新图中这条边都要么被先手和后手同时经过,要么同时不经过。
因此我们考虑这样的算法:我们先将所有边的权值设为 \(r_i\),但是这样会导致某些被先手经过但没被后手经过的边的权值过大,这样就导致方案不优,因此我们需要调整。我们设 \(s_1\) 到 \(x\) 的距离为 \(d1_x\),\(s_2\) 到 \(x\) 的距离为 \(d2_x\),那么对于一条权值自定的边 \((u,v)\),如果 \(d1_u<d2_u\),那么我们就将这条边的权值调整为 \(l_i\) 并重新 dijkstra 一遍算出 \(d1,d2\)。如果最终 \(d1_f<d2_f\),那么说明先手赢了,直接输出每条边的边权,否则我们尝试让先手与后手打成平手,即还是先假设所有边权值都是 \(r_i\),然后每次还是求出 \(s_1,s_2\) 到所有点的最短路并枚举所有权值自定的边 \((u,v)\),如果 \(d1_u\le d2_u\),那么我们就将这条边权值调整为 \(l_i\),最后检查是否有 \(d1_f\le d2_f\),如果成立则输出 DRAW
,否则输出 LOSE
。
为什么这样做是正确的?以前一部分,也就是判断答案是否可能为 WIN
的一半为例,对于每条权值自定的边 \((u,v)\),如果 \(d1_u<d2_u\),那么将这条边权值调整为 \(l_i\) 之后,仍然有 \(d1_u<d2_u\),也就是说在最终的局面中,所有存在一种定边权的方式,满足 \(d1_u<d2_u\) 的权值自定边 \((u,v)\) 的权值都被调至 \(l_i\),而其他权值自定边在任何局面下都有 \(d1_u\ge d2_u\),不会对答案产生任何正面影响,因此最终这个局面肯定是最优的。
时间复杂度 \(mk\log m\)。
84. P3330 [ZJOI2011]看电影
一道出现了 \(10^9+7\) 次的题目(大雾
考虑在 \(k\) 位置后面加入一个 \(k + 1\) 位置并将整个模型变成一个环,那么一种分配方式符合条件当且仅当 \(k+1\) 没有被占。
如果我们每次可以在 \(k+1\) 位置放人,那么理论上来说每个点被占的概率都是相同的,因此满足 \(k+1\) 没有被占的方案数就是 \((k+1)^n·\dfrac{k+1-n}{k+1}=(k+1-n)(k+1)^{n-1}\),答案就是 \(\dfrac{(k+1-n)(k+1)^{n-1}}{k^n}\)。
比较烦的一点是要写高精。
85. P5292 [HNOI2019]校园旅行
首先看到这道题我们可以很自然地想到一个 \(m^2\) 的做法:设 \(can_{i,j}\) 表示 \(i,j\) 之间是否存在符合条件的路径,然后类似 BFS 的思路,扩展到一个 \(can_{i,j}\) 时就遍历一遍 \(i\) 的所有邻居 \(x\) 和 \(j\) 的所有邻居 \(y\),如果 \(s_x=s_y\) 且 \(is_{x,y}=0\) 就令 \(is_{x,y}=1\) 并将 \((x,y)\) 这个二元组放入队列里继续 BFS。显然每对边组成的二元组最多被遍历一次,总复杂度就是 \(\Theta(m^2)\)。
这样显然过不了,考虑优化。注意到这题 \(m\) 级别比 \(n\) 高很多,对于有这样的性质题,一种思路是仔细分析一样是否所有边都是有用的,如果不是那就踢掉那些无用的边,让边数的级别降得和点数一样。此题就是这种思路,我们将边分为三类:两个端点都是 \(0\)、两个端点都是 \(1\)、两个端点一个是 \(0\) 一个是 \(1\)。我们将这三类边拎出来各建一张图,对于每张图,我们考察每个连通块,找出它的一个生成树并将其加入原图,这样边数就降到了 \(\Theta(n)\) 级别。
但这样做其实是错误的,因为对于一个全由 \(0\) 边组成的连通块,如果我们只找出它的生成树,那就默认所有环的大小都是偶数(因为树是一个二分图),但实则不一定,因此我们需要对由全 \(0\) 边和全 \(1\) 边组成的图的每个连通块,跑一遍二分图染色检验其是否是二分图,如果不是那就在这个连通块对应的生成树上加个自环,不难发现这样原图就与新图等价了。然后跑上面的暴力即可。
时间复杂度 \(n^2+m\alpha(n)\)。
86. CF1609F Interesting Sections
讲个笑话,vp 的时候想交这道题的时候 CF 崩掉了,卡了 1h 直到 vp 结束后 3min 才好,好在最后我的第一发提交因为常数太大 T 了,否则就亏大了……
考虑枚举最大值和最小值的 popcount,那么问题等价于,给定一个序列 \(a_i\),其中有一些位置是关键位置,要求有多少个区间,满足其最大值和最小值都是关键位置。
碰到数区间问题无非两个套路:枚举右(左)端点或分治,这次咱们采取前者,我们扫描线式枚举右端点 \(r\),扫描到 \(r\) 时,我们记 \(f_l\) 表示 \([l,r]\) 中最大值是否关键位置 \(+\) \([l,r]\) 中最小值是否是关键位置,那么显然 \(f_l\) 的变化可以通过单调栈求出,那么对于一个右端点 \(r\) 和一个 popcount
\(v\),其对答案的贡献就是 \(f_l=2\) 的 \(l\) 的个数。注意到 \(f_l\) 的上界就是 \(2\),因此这个可以通过区间最大值及其出现次数的线段树维护。
算下复杂度,乍一看这个做法复杂度是 2log 的,但实则不是。因为我们单调栈时修改次数均摊下来是 \(\mathcal O(n)\) 的,而查询我们只用用到根节点存储的值,因此虽然查询次数可以达到 \(n\log v\),单次查询是 \(\mathcal O(1)\) 的这一事实导致复杂度也不算太高,这样总复杂度就是 \(n(\log v+\log n)\),可以通过。
注意常数问题!!!!!1111
87. CF1584G Eligible Segments
由于这篇博客里混入了太多奇怪的东西,2021.11.30 决定将博客名改为“杂题选做”
首先,一个点 \(P_k\) 到线段 \(P_iP_j\) 的最小距离 \(\le R\) 等价于 \(P_k\) 到射线 \(\vec{P_iP_j}\) 的距离 \(\le R\) 且 \(P_k\) 到射线 \(\vec{P_jP_i}\) 的距离也 \(\le R\)。那么我们就设 \(is_{i,j}\) 表示是否对于所有 \(k\) 都有 \(P_k\) 到 \(\vec{P_iP_j}\) 的距离 \(\le R\),那么答案就是满足 \(i<j,is_{i,j}=is_{j,i}=1\) 的二元组 \((i,j)\) 的个数。
考虑如何求 \(is_{i,j}\),我们枚举 \(i\),对于每个 \(k\),我们求出 \(P_i\) 到以 \(P_k\) 为圆心 \(R\) 为半径的圆的两条射线的辐角 \(\theta_1,\theta_2\),那么 \(is_{i,j}=1\) 当且仅当 \(\vec{P_iP_j}\) 的辐角在所有 \([\theta_1,\theta_2]\) 的交中,简单判断一下即可。
时间复杂度 \(n^2\)。
88. CF633G Yash And Trees
这就是我吗?套路题和思维题都不会做吗?/fn/fn/fn
考虑将树拍平变成一个序列,然后以 DFS 序为下标建立一棵线段树,线段树上每一个节点开一个 bitset
维护这个区间内每种数是否出现过。那么每次进行子树加时,就在对应的区间上进行区间加,这样对应在 bitset
上的变化就是 v = (v << x) | (v >> (m - x))
,其中 \(x\) 为增加的量,直接打个标记即可。查询就把对应区间内的 bitset
进行一遍 or
即可。
时间复杂度 \(\dfrac{nm\log n}{\omega}\)。
话说这场的 H 我的题解好像还没有补呢,都 8 个月了,估计这辈子都不会补了(
89. CF1019D Large Triangle
首先狠狠吐槽一句,tm 这题明明三角形格点横纵坐标都是整数,因此三角形面积要么是 .0
要么是 .5
才对啊,为什么偏偏 checker 会说我输出的三角形面积等于 \(xxxx.1\)?我实在是不能理解了,难道选手做题是为了适应 checker 的吗?/fn/fn/fn
一开始想着用向量叉积搞,后来事实证明这种东西对于此题而言没前途(
考虑枚举三角形的一条边 \(AB\),我们考虑将所有点按该点到直线 \(AB\) 的有向距离从小到大排序,如果我们能实现这样的操作,那么我们显然向左向右各二分一下即可检验是否存在面积等于 \(S\) 的三角形。
于是问题转化为,我们如何动态地对于一条线段,维护所有点到直线 \(AB\) 的有向距离排好序后的结果。可以注意到,一个点到直线 \(AB\) 的有向距离,可以转化为,过这个点做 \(AB\) 的平行线后,直线与 \(y\) 轴交点的纵坐标。那么我们考虑一个斜率 \(k\) 从 \(-\infty\) 变到 \(\infty\) 的过程,并设想我们过每个点都做了一条斜率为 \(k\) 的直线,这些直线与 \(y\) 轴各会产生一个交点,我们要比较这些交点的纵坐标的大小。不难发现,对于一个点对 \((i,j)\),满足 \(x_i\ne x_j\) 且当 \(k\) 趋近于 \(-\infty\) 时,\(i\) 的截距 \(<j\) 的截距,那么必定存在一个断点 \(k_0\),满足 \(k<k_0\),\(i\) 的截距 \(<j\) 的截距,对于 \(k>k_0\) 的情况则反过来,那么我们考虑将这个过程用个 vector
存下来并将所有这样的事件按 \(k_0\) 排序,再将所有线段按 \(AB\) 的斜率从小到大排序,然后扫描线段时直接在存储的事件的数组里 two pointers 即可,每次遇到一个“\(i\) 的截距反超了 \(j\) 的截距”的事件,我们就交换 \(i,j\) 的排名。显然此时 \(i,j\) 的排名是相邻的,故我们不用进行多余的调整。这样我们就动态地维护了所有点到 \(AB\) 距离的有向距离的大小。
时间复杂度 \(n^2\log n\)。
90. AT4519 [AGC032D] Rotation Sort
首先考虑一个非常显然的性质:每个数最多被移动一次,否则我们肯定第一次就会将其移动到它最终的位置。发现这个性质之后,我们就可以很自然地将所有数分为两类:被移动过和没被移动过。我们考虑固定住那些没有被移动过的位置,那么对于两个相邻的没有被移动过的位置 \(l,r\) 之间的位置 \(i\),有两种选择:如果 \(a_i>a_r\),那么只能向右移动,否则由于我们钦定它必须移动,那么我们不妨假设剩余位置必须向左移动。这样我们就可以设计出一个 DP:\(dp_i\) 表示考虑了 \(a_1\sim a_i\),且 \(a_i\) 没有被移动所需花费的最小代价,\(\Theta(n)\) 转移即可,总复杂度 \(n^2\)。可以通过线段树优化到 \(n\log n\),但对于此题来说没有必要。
91. P4798 [CEOI2015 Day1]卡尔文球锦标赛
一道非常基础的题,就当刚刚肝了道毒瘤题之后调节一下心情吧(
首先考虑什么样的序列 \(a\) 符合条件。显然 \(a\) 中出现过的数必须是一段从 \(1\) 开始的连续的前缀 \(1,2,3,\cdots,x\) 对吧,并且如果我们把这些数第一次出现的位置拎出来,这些首次出现的位置肯定是单调递增的。容易证明这是充要条件。
发现这个性质之后我们可以很自然地设计出一个类似于数位 DP 的东西:\(dp_{i,j,0/1}\) 表示考虑了前 \(i\) 个位置,目前出现过的最大的数为 \(j\),目前没有 / 有达到上界的方案数,分情况转移即可。直接开数组会 MLE,滚动数组优化一下即可。
时间复杂度 \(n^2\)。
讲个笑话,这个模数貌似不是质数,虽然它长得一脸质数的样子(
92. AT2672 [AGC018C] Coins
首先假设所有人都选了金币,令 \(p_i=B_i-A_i,q_i=C_i-A_i\),那么题目等价于选择 \(y\) 个 \(p_i\) 和 \(z\) 个 \(q_i\),满足它们下标集合交集为空,且选出的这 \(y\) 个 \(p_i\) 个 \(z\) 个 \(q_i\) 的和尽可能大。
考虑反悔贪心,我们先贪心地选出 \(p_i\) 最大的 \(y\) 个数和 \(q_i\) 最大的 \(z\) 个数,但是这样不一定满足“交集非空”的条件,我们假设此时交集大小为 \(cnt\),那么我们考虑执行 \(cnt\) 次操作,每次操作进行一些微调使交集大小减一,不难发现微调的方式无非以下几种:
- 选择一个 \(p_i,q_i\) 都选择的下标 \(i\),和一个 \(p_j,q_j\) 都没选择的下标 \(j\),去掉 \(p_i\) 选上 \(p_j\)
- 选择一个 \(p_i,q_i\) 都选择的下标 \(i\),和一个 \(p_j,q_j\) 都没选择的下标 \(j\),去掉 \(q_i\) 选上 \(q_j\)
- 选择一个 \(p_i,q_i\) 都选择的下标 \(i\),一个选了 \(p_j\) 没选 \(q_j\) 的下标 \(j\),还有一个 \(p_k,q_k\) 都没选择的下标 \(k\),去掉 \(p_i\),把 \(p_j\) 改为 \(q_j\),并选上 \(q_k\)
- 选择一个 \(p_i,q_i\) 都选择的下标 \(i\),一个选了 \(q_j\) 没选 \(p_j\) 的下标 \(j\),还有一个 \(p_k,q_k\) 都没选择的下标 \(k\),去掉 \(q_i\),把 \(q_j\) 改为 \(p_j\),并选上 \(p_k\)
用六个堆维护即可,即维护:
- \(Q_1\) 装有所有 \(p_i,q_i\) 都选的 \(i\) 的 \(-p_i\)
- \(Q_2\) 装有所有 \(p_i,q_i\) 都选的 \(i\) 的 \(-q_i\)
- \(Q_3\) 装有所有 \(p_i,q_i\) 都没选的 \(i\) 的 \(p_i\)
- \(Q_4\) 装有所有 \(p_i,q_i\) 都没选的 \(i\) 的 \(q_i\)
- \(Q_5\) 装有所有选了 \(p_i\) 没选 \(q_i\) 的 \(i\) 的 \(q_i-p_i\)
- \(Q_6\) 装有所有选了 \(q_i\) 没选 \(p_i\) 的 \(i\) 的 \(p_i-q_i\)
时间复杂度 \(n\log n\)。
93. Codeforces Gym 103409 H Popcount Words
首先看到多串匹配相关问题,果断建出 \(q\) 个模式串的 AC 自动机。
如果我们定义 \(W_{i,j}\) 表示 \(0\sim 2^i-1\) 中所有数的 popcount
\(\bmod 2 \oplus j\) 接在一起的结果,其中 \(i\in[0,\lceil\log_2(V)\rceil],j\in[0,1]\)。那么显然所有 \(w(l,r)\) 都可以像线段树区间查询那样拆成不超过 \(2\lceil\log_2(V)\rceil\) 个 \(W_{i,j}\) 拼在一起的结果。因此我们可以将整个文本串看作 \(\mathcal O(n\log V)\) 个 \(W_{i,j}\) 接在一起的结果。
那么我们如何统计 fail 树上每个节点被经过了多少次呢?首先考虑倍增,设 \(to_{i,j,k}\) 表示目前在 fail 树上节点 \(i\),往下读进去一个 \(W_{j,k}\) 后会走到 fail 树上哪个节点。我们再设 \(cnt_{i,j,k}\) 表示有多少次在 \(i\) 处向下接 \(W_{j,k}\) 的机遇,那么我们先按照倍增的套路预处理出 \(to_{i,j,k}\),然后按照顺序依次读进去全部 \(\mathcal O(n\log V)\) 个 \(W_{i,j}\),最后再按照 \(j\) 递减的顺序更新 \(cnt_{i,j,k}\),即用 \(cnt_{i,j,k}\) 去更新 \(cnt_{i,j-1,k}\) 和 \(cnt_{to_{i,j-1,k},j-1,k\oplus 1}\) 即可。
时间复杂度 \((n+\sum|s|)·\log V\)。
94. CF1418F Equal Product
首先思考一下什么样的 \((x_1,x_2,y_1,y_2)\) 符合条件,这里有一条大概用直觉比较容易发现的性质是,对于符合条件的 \((x_1,x_2,y_1,y_2)\),必然存在整数 \(a,b\),使得 \(x_2=\dfrac{x_1}{a}·b\),\(y_2=\dfrac{y_1}{b}·a\) 且 \(\dfrac{x_1}{a},\dfrac{y_1}{b}\) 均为整数。
证明:考虑设 \(d=\gcd(x_1,x_2)\),然后令 \(a=\dfrac{x_1}{d},b=\dfrac{x_2}{d}\)(说白了就是设 \(\dfrac{b}{a}\) 表示 \(\dfrac{x_2}{x_1}\) 约分以后的结果),那么显然 \(\dfrac{x_1}{a}=d\) 为整数,而 \(\dfrac{y_1}{b}·x_1=\dfrac{x_2}{b}·y_2=d·y_2\) 为整数,又根据 \(\gcd(a,b)=1\) 可知 \((x_1,b)=1\),因此必然有 \(b\mid y_1\),证毕。
因此我们考虑枚举 \(x_1\) 时,顺带枚举符合条件的四元组所对应的 \(a\),那么思考一下什么样的二元组 \((y_1,b)\) 会符合条件,归纳一下就是下面三条:
- \(\lceil\dfrac{L}{x_1}\rceil\le y_1\le\min(\lfloor\dfrac{R}{x_1}\rfloor,m)\)。
- \(\dfrac{x_1}{a}·b\le n\)
- \(a<b\)
我们考虑正序枚举 \(x_1\),那么第一条中 \(y_1\) 的范围的左右端点都是不升的,这样我们可以通过 two pointers 将所有符合条件的二元组 \((b,y_1)\) 扔进一个 set
中,对于后两条限制,显然在符合第三条限制的前提下,\(b\) 最小的那个最有可能符合条件二,因此我们直接在 set
中 lower_bound
检验即可。
算下复杂度,set
有个 log,而我们 \(x,a\) 的总枚举量是调和级数级别的,也就是 \(n\ln n\),因此总复杂度 \(n\ln n\log n\),可以通过。
95. CF1519E Off by One
由于每个点必须要移动,因此我们考虑对于每个点 \(i\),求出其向上和向右移动后得到的两个点 \(P_i,Q_i\),然后将所有出现过的斜率看作一个点并在 \(P_i,Q_i\) 的斜率所对应的点之间连边。这样问题可以转化为,给你一张图,要你选出一些不相交的二元组 \((e1_i,e2_i)\),满足选出的二元组中两两之间没有公共元素且 \(e1_i,e2_i\) 之间有公共点,要你求最多能选出多少个二元组。
针对上面的问题,我们首先大胆猜测:对于每个连通块,假设连通块中有 \(e\) 条边,那么该连通块中最多可以选出 \(\lfloor\dfrac{e}{2}\rfloor\) 个二元组,即,假设图中有 \(k\) 个连通块,第 \(i\) 个连通块中有 \(e_i\) 条边,那么答案就是 \(\sum\limits_{i=1}^k\lfloor\dfrac{e_i}{2}\rfloor\)。
事实的确如此,考虑如何构造:对于每个连通块,我们先对其进行一遍 DFS,也就是找出它的一棵 DFS 树(虽然我们并不用显示地将树建出来,但是大体思想就是如此),然后对于每个点,有可能所有与其相连的边已经全部匹配完,也有可能与其相连的边中,恰有一条边没有被匹配(如果出现了多余两条边没有被匹配,那么我们可以贪心地将这两条边配对,这样肯定更优)。因此我们记 \(mch_u\) 表示与 \(u\) 相连的边中,没有被匹配的边的编号,特别地,\(mch_u=0\) 则表示所有与 \(u\) 相连的边都被匹配。那么我们考虑 DFS \(u\) 的一个儿子 \(v\) 时,分情况讨论:
- 如果 \(mch_v\ne 0\),则将 \(u,v\) 之间的边与 \(mch_v\) 配对并令 \(mch_v=0\)
- 否则,如果 \(mch_u\ne 0\),则将 \(u,v\) 之间的边与 \(mch_u\) 配对并令 \(mch_u=0\)
- 否则令 \(mch_u\) 为 \(u,v\) 之间的边的编号。
如此贪心下去即可,总复杂度 \(n\log n\),瓶颈在于求出所有出现过的斜率。可能可以做到 \(\mathcal O(n)\)。
96. CF1609G A Stroll Around the Matrix
u1s1 感觉这个题其实还挺一眼的吧,不知道怎么被评到 3k 的.jpg(
首先考虑什么样的路径是最优路径。我们先不妨假设我们先一直向右走,再一直向下走,即 \((1,1)\to(1,2)\to\cdots\to(1,m)\to(2,m)\to\cdots\to(n,m)\),但是这样显然不一定是最优解,因此考虑调整。调整的第一步显然是将 \((1,m-1)\to(1,m)\to(2,m)\) 调整为 \((1,m-1)\to(2,m-1)\to(2,m)\),显然后者代价比前者更优,当且仅当 \(a_2+b_{m-1}<a_1+b_m\)。再者就是将 \((1,m-2)\to(1,m-1)\to(2,m-1)\) 调整为 \((1,m-2)\to(2,m-2)\to(2,m-1)\),以及 \((2,m-1)\to(2,m)\to(3,m)\) 调整为 \((2,m-1)\to(3,m-1)\to(3,m)\),以此类推。按照这样的方式继续手玩下去可以发现,在最终的状态中,假设我们在点 \((i,j)\),那么我们会往下走,当且仅当 \(j=m\),或者 \(i\ne n\) 且 \(a_{i+1}-a_i<b_{j+1}-b_j\)。
我们考虑设 \(pos_i\) 表示我们处于第 \(i\) 行时,会在哪个位置首次向下走,由于 \(n\) 很小并且题目中 \(a,b\) 序列都是下凸的,因此对于同一行 \(i\),必然存在一个断点 \(j\),使得对于 \(j\) 左边所有位置,当我们位于 \((i,j)\) 时都会向右走,而对于 \(j\) 右边所有位置,当我们位于 \((i,j)\) 时都会向下走。且 \(pos\) 数组也是单调不降的。这样一来问题就好办了,由于 \(n\) 很小,因此对于每次修改,改完之后都可以直接线段树二分修改 \(pos\) 数组,而答案即为 \(\sum\limits_{i=1}^n(a_i·(pos_i-pos_{i-1}+1)+\sum\limits_{j=pos_{i-1}}^{pos_i}b_j)\),这个也可以每次 \(\mathcal O(n\log m)\) 地求。比较麻烦的是要实现单点加求三阶前缀和,用树状数组维护平方项、一次项和常数项能够获得常数较小的实现。
时间复杂度 \(\Theta(nm\log m)\)。
97. NFLSOJ #795 【五校国集集训 Day1】数学题(math)
首先考虑求出给定的 \(n\) 个向量的一组基 \(\mathcal B\)。那么非常显然的一个性质是,对于不在 \(\mathcal B\) 中的向量,如果我们翻转其中任意一位上的值,矩阵的秩肯定不会减小,因为矩阵仍存在线性无关的向量集合 \(\mathcal B\)。而我们发现,对于 \(\mathcal B\) 中的某些向量,这个性质也是成立的,比方说给出的向量集合为 \(\{100,011,111\}\),我们通过一遍线性基求出的基 \(\mathcal B = \{100,011\}\),但实际上,不论我们去掉三个向量中的哪一个,剩余部分的秩仍然是 \(2\),也就是说不论我们翻转哪一个位置,矩阵的秩总是不降的。
那我们如何找出所有满足“翻转其中任意一位,矩阵的秩都不降”的向量呢?首先不在 \(\mathcal B\) 中的向量肯定要归为其中,而对于在 \(\mathcal B\) 中的向量,我们假设 \(\mathcal B = \{x_{b_1},x_{b_2},\cdots,x_{b_k}\}\),并将所有不在 \(\mathcal B\) 中的向量都表示为 \(\mathcal B\) 中向量的线性组合,即假设 \(x_i=c_{i,1}x_{b_1}+c_{i,2}x_{b_2}+\cdots+c_{i,k}x_{b_k}\),其中 \(c_{i,j}\in\{0,1\}\),那么一个 \(x_{b_j}\) 符合上述要求,当且仅当 \(\exists i,s.t.c_{i,j}=1\),因为就算把 \(x_{b_j}\) 去掉之后,加入符合上述要求的 \(x_i\),得到的向量集仍是线性无关的。
而我们还可以发现一个性质,就是对于符合上面要求的向量,它们的答案都是相同的。具体来说我们考察每个 \(e_j\),即只有第 \(j\) 维为 \(1\) 的向量,如果它在 \(\mathcal B\) 生成的空间中,那么说明对于符合上面要求的向量,它与 \(e_j\) 的和也在 \(\mathcal B\) 生成的空间中,所有这些向量的答案的第 \(j\) 位就是 \(0\),否则所有这些向量第 \(j\) 位的答案就是 \(+\)。
那对于别的向量,也就是去掉这个向量后,矩阵的秩必然减小的向量呢,首先一个显然的性质:翻转这些向量的任何一位后,矩阵的秩必然不增,因为去掉这个向量后,矩阵的秩减少 \(1\),而加入一个向量最多使矩阵的秩增加 \(1\)。那么翻转什么样的位后,答案减小 \(1\) 呢?我们还是考虑将 \(e_j\) 拆成 \(\mathcal B\) 中元素的线性组合。如果 \(e_j\) 无法表示,那么秩肯定不变,否则,如果 \(e_j\) 的表示中包含 \(x_i\),那么我们考虑再将 \(x_i+e_j\) 表示成 \(\mathcal B\) 中元素的线性组合,显然 \(x_i+e_j\) 的线性组合中不会包含 \(x_i\),因为 \(x_i\) 的表达式中有个 \(x_i\),\(e_j\) 的表达式中也有个 \(x_i\),二者相加,在模 \(2\) 意义下消掉了,而其他向量的表示中也没有 \(x_i\),因此矩阵的秩减小,否则不难说明矩阵的秩不变。
用 bitset
模拟上面的过程即可,时间复杂度 \(\dfrac{n^3}{\omega}\),如果视 \(n,m\) 同阶。
98. CF1530G What a Reversal
What a Problem!
首先考虑在变换前后有没有什么量是不变的。显然 \(1\) 的个数肯定不会变对吧,如果 \(s,t\) 中 \(1\) 的个数不同那就直接 GG 了。这个直接特判一下即可。
我们记 \(s,t\) 中 \(1\) 的个数为 \(m\),对于 \(k=0\) 或 \(k>m\) 的情况,显然只有 \(s,t\) 完全相同才有可能有解,这个特判一下即可。对于 \(k=m\) 的情况我们也需特判一下,这个大概就分翻一次、翻两次、翻三次分类讨论一下,可能细节略有点繁琐。
下面重点讨论 \(k<m\) 的情况,首先发现操作可逆,因此我们按照套路将 \(s,t\) 全变成一个字符串,然后正序输出 \(s\) 的操作序列并倒序输出 \(t\) 的操作序列。考虑一次操作的本质是什么,我们假设 \(s\) 的 \(1\) 的位置分别是 \(p_1,p_2,\cdots,p_m\),方便起见假设 \(p_0=0,p_{m+1}=n+1\),我们再设 \(d_i=p_{i+1}-p_i-1\),那么可以发现一次操作等价于:
- 选择一个 \(i\in[0,m-k]\),reverse 子段 \(d_{i+1},d_{i+2},\cdots,d_{i+k-1}\),同时选择一个 \(j\in[-d_i,d_{i+k}]\),并令 \(d_i\) 加上 \(j\),\(d_{i+k}\) 减去 \(j\)。
下面考虑怎样构造,首先是 \(k\) 是奇数的情况,我们考虑将两个字符串都调整至 \(d_0=n-m,d_i=0(i\in[1,m])\) 的状态。我们首先先将 \(d_{k+1},d_{k+2},\cdots,d_m\) 归零,这个就每次选择 \(j=d_{i+k}\) 即可清空 \(d_{i+k}\)。然后我们考虑对于奇数步,我们令 \(i=0,j=d_k\),这样相当于翻转 \(d_1\sim d_{k-1}\) 并将 \(d_k\) 清空全部送给 \(d_0\);对于偶数步,我们选择 \(i=1,j=d_{k+1}=0\),这样相当于翻转 \(d_2\sim d_k\),不难发现这样操作下去,\(d\) 数组会依次发生以下变化(其中红色代表对应的 \(d\) 值已经变为 \(0\):
- \(d_0,d_{k-1},d_{k-2},\cdots,d_1,\color{red}{d_k}\)
- \(d_0,d_{k-1},\color{red}{d_k}\color{black}{,d_{1},d_2,\cdots,d_{k-2}}\)
- \(d_0,d_{k-3},d_{k-4},\cdots,d_1,\color{red}d_k\color{black},d_{k-1},\color{red}d_{k-2}\)
- \(d_0,d_{k-3},\color{red}{d_{k-2}}\color{black}{,d_{k-1},}\color{red}{d_k}\color{black}{,d_1,d_2,\cdots,d_{k-4}}\)
不难发现在上面的过程中,咱们采用每一轮隔一个清一个的策略,即在奇数次操作依次将 \(d_k,d_{k-2},d_{k-4}\cdots,d_1,d_{k-1},d_{k-3},\cdots d_2\) 清空,由于 \(k\) 是奇数,故每个 \(d_i\) 都会被清到,因此进行 \(2k\) 次操作即可清空 \(d_1\sim d_k\),总操作数 \(2k+(m-k)=m+k\le 2n\)。
接下来考虑偶数的清空,手玩一下可以发现 \(k\) 为偶数时不一定有解,因为不论你怎么 reverse,都有奇数位上的 \(d_i\) 之和不变,偶数位上也是如此,因此如果 \(s,t\) 奇数位上的 \(d\) 之和不同那就直接 GG 了,否则我们考虑如下构造方式:
- 首先还是将 \(d_{k+1}\sim d_n\) 全部清空,构造方式同 \(k\) 为奇数的清空。
- 然后在奇数轮我们还是选择 \(i=0,j=d_k\),在偶数轮我们则选择 \(i=1,j=-d_1\)。
我们还是手动模拟一下上面的过程:
- \(d_0,d_{k-1},d_{k-2},\cdots,d_1,\color{red}{d_k}\color{black},d_{k+1}=0\)
- \(d_0,\color{red}{d_{k-1},d_k}\color{black},d_{k-2},\cdots,d_1,d_{k+1}\)
- \(d_0,d_2,d_3,\cdots,d_{k-2},\color{red}{d_{k},d_{k-1},d_1}\color{black},d_{k+1}\)
- \(d_0,\color{red}{d_2,d_1,d_{k-1},d_k}\color{black},d_{k-2},d_{k-3},\cdots,d_4,d_3,d_{k+1}\)
不难发现在上面的过程中,我们不断把奇数位上的 \(d\) 丢给 \(d_{k+1}\),把偶数位上的 \(d\) 丢给 \(d_0\),因此最后得到的一定是 \(x,0,0,0,\cdots,0,y,0,0,\cdots\) 的形式。符合要求。
时间复杂度 \(n^2\),瓶颈在于每次操作后都要 reverse 重新算 \(p,d\)。
99. CF1530H Turing's Award
咦?时隔 INF 天,tzc 竟然来补题解了,incredible(
首先考虑将整个过程倒过来处理,问题转化为有一条数轴,你当前在 \(0\) 的位置,有一个排列,每次你可以走到相邻两个位置中的一个,如果那个位置上没有数就在那个位置上填上 \(p_i\),求得到的 LIS 的最大值。
不难发现最优策略中,任意时刻肯定是恰有一个区间上有数,并且对于我们不钦定在 LIS 上的数我们肯定不会把它写到纸上,否则从区间的一端走到另一端所需的代价会更大。考虑以此为状态设计 DP。设 \(dpl_{i,j}\) 表示目前人在左边,LIS 长度为 \(j\),最左边的在 LIS 上的数为 \(i\),最右端的数的最小值,再设 \(dpr_{i,j}\) 表示目前人在右边,LIS 长度为 \(j\),最右边的在 LIS 上的数为 \(i\),最左端的数的最大值。考虑如何转移,以 \(dpl\) 为例,\(dpr\) 道理类似:
- 如果上一步还在左边,那么有 \(dpl_{i’,j-1}\to dpl_{i,j}\),能进行这样的转移的条件是 \(i’>i\) 且 \(pos_{i’}>pos_i\),其中 \(pos_x\) 表示 \(x\) 这个数在排列中的位置。
- 如果上一步在右边,那么有 \(i’\to dpl_{i,j}\),能进行这样的转移的条件是 \(dpr_{i’,j-1}>i\) 且 \(pos_{i’}-pos_i\ge j-1\)
直接枚举 \(i,j,i’\) 转移是三方的,不过注意到转移可以写成前缀 \(\max/\min\) 的形式,因此可以用树状数组找出最优决策点,复杂度变成了 \(n^2\log n\),但还是不够。注意到题面中有个“排列 \(p\) 随机生成”的条件。根据经典结论,随机排列的 LIS 长度期望是根号级别的,因此我们猜测答案期望也是根号级别的,事实确实如此。实践证明 \(j\) 枚举到 \(285\) 即可,这样复杂度就变成了 \(285n\log n\),常数略大,但由于时限很大,可以通过。
具体实现时还有不少细节需要注意,比如此题边界条件非常值得思考,不能简单地 \(dpl_{i,1}=dpr_{i,1}=i\),因为无论如何 \(p_n\) 都是要写出来的,因此要分 \(p_n\) 在 LIS 上和不在 LIS 上处理。
100. P6845 [CEOI2019] Dynamic Diameter
简单题。然鹅我一开始竟然不会,ymx 竟然一开始想 LCT,wjz 竟然一开始想动态 DP,震撼震撼(
考虑经典结论:点集的并的直径属于点集的直径的并,这样我们可以在 \(\mathcal O(\log n)\) 的时间内通过两个点集 \(U,V\) 的直径合并得到 \(U\cup V\) 的直径,然后 DFS 序+线段树维护区间直径即可,修改一条边的边权时,我们只用更新包含这个点的区间的信息即可。
时间复杂度 \(n\log^2n\)。