CF 做题记录

  • CF1534G A New Beginning

有个性质是,一条答案路径,它与经过点(x,y)的斜率为-1的一次函数(也就是对角线)的交点,就是它给(x,y)打标记的最佳位置。证明就是,从交点往上下左右走都会让答案不变/变大

于是从对角线上dp,太麻烦了就转45度转为在直线上dp

dp方程往直线上走走就知道了,画出来发现是个区间取min然后加个一次函数,显然函数是个凸包,直接上 slope trick 即可

  • CF1553H XOR and Distance

考虑对于每个 x,枚举相同的前缀和不同的后缀来算答案

\[f(d,x)= \min\limits_{a_i \oplus x<2^d,a_j \oplus x<2^d} \{|a_i\oplus x-a_j\oplus x|\} \]

\(d-1\) 位和 x 相同的贡献显然就是 \(f(d-1,x)\)

\(d-1\) 位和 x 不同的贡献显然就是 \(f(d-1,x\oplus 2^{d-1})\)

仅需考虑 \(d-1\) 位和 x 相同的,以及与 \(d-1\) 位和 x 不同的两个数的差的最小值。

知道 \(min(d,x)\)\(max(d,x)\) 就可以做了,具体推导方式和 \(f\) 差不多

  • CF1271F Divide The Students

如果学生参加一门课,那么随便分配

如果学生参加三门课,那么把三门课的分配掉,剩下的也是随便分配

那么剩下的就是两门课的选手怎么分配,直接枚举,\(\mathcal{O}(n^3)\) 加剪枝过 3000,小编也很好奇

  • CF1562F Tubular Bells

如果找到了一个大于中间数的质数和它的值,只需 \(n-1\) 次询问即可

那么问题在于如何 5000 次找出一个质数,由于质数规模大约为 \(\frac{n}{\ln n}\) 左右,所以随到的概率是 \(\frac{1}{\ln n}\),还是挺高的。

至于如何判断这个数字是一个质数,还是随机,随机若干个数字询问,取这些数字的 \(\gcd\),如果 \(\gcd\) 是质数显然就不是合数。最坏情况下,质数判错的概率为 \((\frac{1}{2})^k\),其中 \(k\) 为随机的概率。

\(k\) 取 20 的话可以通过此题。

然而还有情况就是没有质数,即 \(n\le 100\) 的情况,直接暴力做就是了

  • CF1468B Bakery

显然答案随着 k 的增加而减少,考虑在 k 减少时维护几个天数的区间段,同一个段内的可以把造的面包全部卖完,如果因为 k 减少而卖不完面包,就往后合并

考虑用 set 来维护这些区间段,答案就对区间长度取max即可。

代码

  • CF878D Magic Breeding

考虑值全为 0/1 的时候怎么做,显然对于 \(n\) 个不同的位,\(k\) 个数字最多有 \(\min \{n,2^k\}\) 种不同的取值。

比如输入为

001
110
101

的时候,有 011010101 三个位上的不同取值。

于是我们就可以把不同的位看成不同的取值,\(f_{i,S}\) 表示 \(k\) 个数字的取值为 \(S\) 时,第 \(i\) 个生物的答案。

\(\max / \min\) 操作就可以直接看成二进制的 或/与 。

值域扩展成 \(10^9\) 时可以直接枚举答案 ans,把 \(<\) ans 的数字看成是 \(0\),$\ge $ ans 的数字看成是 \(1\),然后根据 \(f_{i}\) 来判断答案是否 \(\ge\) ans。

以上过程可以用 bitset 来加速,时间复杂度 \(\mathcal{O}(\frac{q2^k}{\omega})\)

  • CF303E Random Ranking

首先有个 \(\mathcal{O}(n^5)\) 做法,把数字离散化然后对着段内的数去 dp,枚举位置 x 和 x 所在的段 v,每个数字有三种选择:

  1. 在段 v 前面。那么排名直接加一

  2. 在段 v 后面。那么排名不变

  3. 在段 v 里面。设除 x 外在段 v 里的数字有 j 个,那么 x 有 \(\dfrac{1}{j+1}\) 的概率成为段内排名为 k 的数字(其中 k 是 \(\le j+1\) 的任意数字) ,由于所有值都是实数,不存在两个点相同,所以是对的。

于是就可以 dp,时间复杂度 \(\mathcal{O}(n^5)\)

然后发现这个 dp 和 x 本身没啥关系,只需要求出除了 x 以外所有数的 dp 数组,于是可以直接分治,时间复杂度 \(\mathcal{O}(n^4 \log n)\)

  • CF1386C Joker

考虑离线,对于每个 \(i\) 处理出一个最大的 \(ans_i\) 使得 \([1,i-1] \cap [ans_i+1,m]\) 有奇环,这样每个询问就可以 \(\mathcal{O}(1)\) 解决。

笨一点的方法是,考虑 \(ans_i\) 是不减的,所以直接 双指针 + LCT 就秒杀了。

如果代码想写得少一点就直接整体二分。

  • CF1359F RC Kaboom Show

二分答案,然后判断区间内有没有相交线段

可以直接扫描线,然后插入删除的时候判断是否和上下两条线段有交即可。具体用 set 维护,时间复杂度不知道为什么是对的。

  • CF1081G Mergesort Strikes Back

众所周知,归并排序把前缀最大值划分的块按块头排序。

我们把 \(k\) 层归并划分出的那些块拿出来算贡献。

考虑两个块合并后,第一个块中位置 \(i\) 和第二个块位置 \(j\) 产生逆序对的概率。

如果 \(i\)\(j\) 是两个块前缀 \(i+j\) 个数字的最大值,那么必然无解。

否则,\(i\)\(j\) 根据前缀最大值排序,\(i\)\(j\) 前面或后面,两者产生逆序对的概率显然相同,都是 \(\dfrac{1}{2}\)

于是 \(i\)\(j\) 产生逆序对的概率就是 \(\dfrac{1}{2}-\dfrac{1}{i+j}\)

由于按前缀最大值排序后,前缀最大值还是前缀最大值,所以块合并后算和把所有块拿出来两两算是一样的,我们直接把所有块拿出来两两算就行了。

由于本质不同的块的数量最多只有 \(2\),所以复杂度很优秀。

  • CF1580D Subsequence

实际难度并没有 2900

首先我们考虑给你一个子序列怎么算贡献,就是把每个 \([b_{i},b_{i+1}]\) 的最小值拿出来做个笛卡尔树算算贡献就行了,然后我们发现这些最小值都在笛卡尔树上,我们相当于是对 \(a_{b_i}\) 的虚树的笛卡尔树算贡献。

于是我们可以在笛卡尔树上 dp,于是你就秒杀了 2900 的题。

  • CF1550F Jumping Around

求最小瓶颈生成树,\(i\)\(j\) 的 dis 为 \(||a_i-a_j|-d|\),根据 \(i\)\(j\) 的大小分类讨论,然后做一遍 boruvka 就行了。

  • CF1553G Common Divisor Graph

操作次数显然 \(\le 2\),只要给 s 做一次,给 t 做一次就行了,这样它们的 gcd 肯定会包含一个 2。

接下来就是判断是否一次操作就能搞定,这个就并查集随便做

  • CF444E DZY Loves Planting

这题就是让每个点 \(i\) 匹配一个点 \(p_i\),让 \(\min\{dis(i,p_i)\}\) 最大,我们考虑二分这个 \(\min\{dis(i,p_i)\}\),我们设二分的这个答案为 \(mid\),那么问题转化为每个点 \(i\) 都要连出一个点,满足这个点到 \(i\) 至少有一条 \(\ge mid\) 的边。而且每个点被连的次数不超过 \(x_i\)

那么对于我们可以考虑把 \(< mid\) 的每条边缩成一个连通块,内部的点不能互相连,于是就要满足 \(\sum x_i\) 减去连通块内的 \(x_i\) 之和要 \(\ge\) 连通块的大小。

这些就可以用并查集来实现

  • CF930E Coins Exhibition

考虑容斥。一个指数级做法是直接钦定某些区间不满足条件,然后算它们的并集就是了。然后它们的容斥系数是 \((-1)^{\text{区间个数}}\times 2^{n-\text{并集大小}}\),把这个拆解一下就是 \((-1)^{\text{区间个数}} \times \dfrac{1}{2^{\text{并集大小}}}\),需要值得一提的是区间如果有相交的,那么它们的种类应当相同。

\(f_{i}\) 表示前 \(i\) 个区间里第 \(i\) 个区间必须选,其他区间随便选的容斥系数之和。

对于相离的区间,显然容斥系数就是 \(-\dfrac{1}{2^{r_i-l_i+1}}\),dp 算下前缀和就随便搞。

对于相交的区间,显然如果这个区间要考虑的话,和 \(i\) 应当是同一个种类的区间。然后我们发现并集是以 \(r_i-r_j\) 的形式一个个增加的,所以我们就算一下前缀和乘上 \(2^{-r_j}\) 就好了,dp 过程也是差不多的。

包含情况就很复杂,然而我们发现一个区间 \(i\) 如果包含某个区间,那么这个区间对容斥系数的贡献是 \(0\),一种处理方法是把区间排序后让 \(l_i\) 取前缀 \(\max\),这样就可以把包含情况处理成相交情况,且对容斥系数的贡献仍然是 \(0\)

code

  • CF1572C Paint

显然如果颜色互不相同答案就是 \(n-1\),那么考虑颜色有相同的情况怎么做

我们仍然设当前答案为 \(n-1\),但是这样会让答案偏大,我们可以考虑相同的颜色对减少答案的贡献。如果一个二元组 \((i,j)\) 满足 \(i\)\(j\) 颜色相同且 \([i+1,j-1]\) 被染成同一个颜色,那么 \(i\)\(j\) 只需要被染色 \(1\) 次即可。

如果把二元组看成区间的话,那么这些二元组显然除了端点以外就不能相交,所以我们可以对这些二元组进行区间 dp。

转移方程是

\[f_{l,r}=\max\limits_{a_k=a_l,l\le k\le r}\{f_{l+1,k-1}+f_{k,r}+1\} \]

如果 \(l\) 不成为二元组的话就有 \(f_{l,r}=\max\{f_{l,r},f_{l+1,r}\}\)

  • CF1491H Yuezheng Ling and Dynamic Tree

考虑分块怎么做,直接按序列分块然后像树链剖分的过程那样去维护,具体一点就是树链剖分有一个数组叫 \(top\) ,表示一个点只从重边向上能走到的最远祖先,这里我们就维护一个 \(f_i\),表示一个点只在块内走向上能走到的最远祖先。

至于维护好数组之后怎么求 lca,也是和树剖差不多,就是两个点先跳到同一条重链(\(f_i\) 相等),然后树剖到这里就停止了,因为此时的 lca 就是深度比较大的点,但是在本题过程中过程尚未停止,我们直接暴力跳父亲就好了。

如果块长为 \(B\) 的话单次查询的复杂度就是 \(\mathcal{O}(B+\dfrac{n}{B})\)

问题转化成如何维护 \(f\),显然如果是散块可以直接暴力做。

整块的话,如果减的次数 \(>\) 块长,内部的 \(f_i=i\),所以一个块只会被减掉 \(\mathcal{O}(B)\) 次。复杂度是 \(\mathcal{O}(nB)\)

\(B=\sqrt{n}\) 复杂度就是 \(n\sqrt{n}\) 了。

  • CF1140G Double Tree

路径肯定可以拆成 \(u \to lca,v\to lca\),无非就是两个点最后走到的 lca 必须在同一棵树上。

考虑一棵树中点走向 lca 的过程是怎样的,肯定是先走向一个点来换树,然后从这个点往上走,再走向一个点来换树,然后再从这个点往上走,然后以此类推。

可以考虑用倍增来维护这个东西,\(f_{u,j,x,y}\) 表示 \(u\) 往上走 \(2^j\) 步,\(u\) 本身从第 \(x\) 棵树走到第 \(y\) 棵树的最小路径长度是多少,可以写个类似矩阵乘的东西去维护。

由于有个“走向一个点来换树”的东西,我们直接换根 dp 来考虑每个点换树所需要的最小路径长度,然后直接搞就行了。

  • CF1055E Tree and XOR

由于路径的 xor 实际上就是两点到根的 xor 和的 xor,所以本题实际上就是问你 k 小 \(a_i \oplus a_j\)

考虑在 trie 树上直接枚举答案每一位,对于每个点维护一个当前 k 位 \(\oplus \ a_i=ans\) 的点,然后就可以通过这个来快速判断答案。

发现直接搞 trie 树空间会爆炸,由于 trie 树前面几层没用,只维护两层的点就好了。

  • CF1404D Game of Pairs

考虑如果是 A 如何必胜,可以让 B 如何选择模 n 都相同,就组 n 组 \((i,n+i)\) ,如果 n 是偶数则有 \(\dfrac{n(n+1)}{2} \equiv 1 \pmod n\)

于是 n 是偶数 A 必胜,反之猜测 B 必胜。

\((i,n+i)\) 和 A 给定的二元组进行连边,肯定没有奇环且每个点的度数为二,直接二分图染色就行了,染出来的点 \(\mod {2n}\) 肯定等于 n 或 0,直接搞就行了

  • CF1455G Forbidden Value

发现这是一个树形结构,然后直接树上 dp ,用个线段树合并来优化就可以了。

  • CF1455F String and Operations

发现 \(i\) 位最多会对 \([i-2,i+1]\) 位的字符造成影响,那我们就对这些字符 dp 即可。

\(f_i\)\([i-4,i-1]\) 字符的最小字符串,然后直接 dp 就行了。

实现可能比较复杂。

  • CF1446D Frequency Problem

考虑 D1 暴力怎么做,我们发现最大区间里,其中一个众数必然是全局众数,如果区间里的众数不是全局众数,那我们可以通过扩展区间来让其中一个众数变成全局众数。

所以我们可以考虑枚举另一个众数,两个众数能同时出现在一个区间里需要满足两者的出现次数相同,所以我们直接算和为 0 的最长区间即可。但是还需要满足一个条件就是两者皆为众数,根据证明过程,如果两者都不是众数的话显然这个区间就不是最优区间。

再考虑怎么优化,我们可以根号分治,对于众数大小 \(\ge \sqrt{n}\) 的可以直接暴力,否则可以直接枚举众数大小来双指针。

时间复杂度 \(\mathcal{O}(n\sqrt{n})\)

  • CF1458D Flip and Reverse

如果把 \(0\) 看成 \(-1\)\(1\) 看成 \(1\),那么 \([l,r]\) 能翻转的一个必要条件就是 \(s_l=s_r\)(s 是前缀和),如果我们把 \(s_i\) 看成节点的话,那么这就是一个环。

手动模拟一下就能发现,一次操作实际上是把走简单环的顺序翻转。比如说我们走简单环 \(P_1,P_2\),操作过后就变成走环 \(P_2,P_1\)

于是我们可以通过一些操作让我们走环的顺序是任意的,问题直接转化为走最小字典序的欧拉路。

问题不太好求,但是此题性质特殊,每个点本质不同的出边最多只有两条,如果出边有两条,那么必有一条能回来。我们直接根据这个性质做题就行了。

代码

  • CF1543E The Final Pursuit

考虑每个点的出点要么是该点的子集,要么该点是此点的子集,我们直接钦定每个点的层数(即与 0 间的距离),然后层数高的数就是出边的层数低的点的 or。

至于染色,发现每个点都会出现 \(\dfrac{2^n}{n}\) 次,所以 \(n\) 必然是 2 的次幂。

由于 \([0\ldots2^{k}-1]\) 异或一个数后排列仍然一样。所以如果一个颜色是 \(x\),让出边的点的颜色等于 \(x\) 异或边的权值就行了。

  • CF1508E Tree Calendar

题目很好,但我就是不会 /ll

发现一个点会往编号最小的子树走,也就是说 swap 过后一个点仍然满足该点是子树内未标号点中编号最小的。

根据这个性质我们可以直接确定原先的 dfn 序。

显然 \(a_1-1\) 是当前正在移动的点,\(1\sim a_1-2\) 已经移动完毕,我们可以求出它们的位置(手玩过后发现是后序遍历)

至于 \(a_1-1\) 本身,我们需要特判它一直往下走能不能到算出来的位置

然后我们把 \(a_1-1\) swap 回原来的位置,这样 \(a_1\sim n\) 的位置可以直接算,直接判断就行了。

上面那一句有些人没有判断于是被我叉了(

  • CF1453F Even Harder

直接 dp,\(f_{i,j}\) 表示前 \(i\) 个数,除 \(i\) 外没删掉的点最多能走到 j ,且只有一条路径的最小修改值

\(f_{i,j+a_j}=\min\limits_{j+a_j\ge i,k<i}\{f_{j,k}+cnt_{i+1,j-1}\}\)

其中 \(cnt_{i+1,j-1}\) 表示 \([i+1,j-1]\) 中能到 \(i\) 的位置。

  • CF1326F2 Wise Men (Hard Version)

题是好题,但我就是不会/ll

可以直接容斥,让 \(s_i=1\) 的必须满足条件,\(s_i=0\) 的不需要满足。至于怎么算回来直接高维前缀和反过来算就可以了。

至于怎么算,可以发现这个东西等价于让你搞几个长度为 \(a_1,a_2,a_3,\ldots,a_k\) 的不相交的,且总和为 \(n\) 的链,所以本质不同的状态数量只有 \(P(n)\) 个,其中 \(P(n)=\) \(n\) 的整数分解方案数。

于是我们考虑一个状态怎么算,我们发现两条限制实际上就是一样的,即让集合的或的大小等于 \(n\),我们还是直接容斥,直接钦定某些位置或不到,剩下的就直接高维前缀和算一算就行了。

  • CF613E Puzzle Lover

一个路径可以分为三段:

  • 从起点开始往左走一段再往回走到起点这一列
  • 从起点往右一直走到终点
  • 从终点开始往右走一段再往回走到终点这一列

对于第一个直接 \(n^2\) 枚举然后计入 dp,第二个直接 dp,第三个就和第二个的 dp 拼起来算就行了。

具体实现可能比较复杂,代码

  • CF1508D Swap Pass

考虑一个置换怎么做,我们直接钦定一个点,对其他点连成一个菊花,然后每次 swap 都是这个点和其他点,就可以了。

至于多个置换怎么做,可以 swap 两个置换中的一个点,这样搞就能让它们组成一个置换。

但是这样可能会让菊花和其他 swap 相交,我们让左下角的点成为菊花中心,把其他点按极角排序,让 swap 的两个点为排序后相邻的点,这样 swap 的边就一定不会和菊花相交。

  • CF986E Prince's Problem

发现不同质因子是 n log n 级别的,我们直接离线把每个质因子用树状数组维护一下次数就行了,时间复杂度 \(\mathcal{O}(n\log^2n)\)

  • CF1495E Qingshan and Daniel

肯定有组机器人把牌打完了,我们设这个机器人为 \(B\),其他组机器人为 \(A\)

那么打牌的形式肯定是 \(ABABAB...AB\) 或者 \(BAB...ABAB\)

那我们先判一下哪组机器人把牌打完了,由于如果一个机器人把牌打了,它右边的有牌打的机器人就会把牌打出去,而我们只需要知道每个机器人打了多少牌,于是问题转化成了匹配问题,我们在环上做一次匹配就行了。

  • CF1491G Switch and Flip

跟 Swap Pass 差不多,考虑只有一个置换环怎么做

以一个点为中心不断 Swap,然而这样做最后会留下两个已翻转的点。

那我们考虑 Swap 的过程在环的大小只剩 2 的时候停止,然后剩下两个已翻转的点和一个未翻转的点,我们直接手玩 n=3 的情况即可 (然而我不会)

次数是 \(n+1\) 级别的,如果环有很多个就不行了

我们考虑把两个环用 swap 的方式合并在一起,然后就不会留下两个已翻转的点,就能随便搞。

  • CF1175G Yet Another Partiton Problem

考虑 dp,如果直接转移的话很不可搞,可以考虑分治,考虑 \([l,mid]\)\([mid+1,r]\) 的贡献

分类讨论 \(\max\) 的位置在哪里,然后李超树 + two-pointers 维护

  • CF1503D Flip the Cards

考虑如何判断合法,如果有一张牌满足两面 \(\le n\) ,或者两面 \(\ge n\),就无解,比较显然

否则就把牌拿出来先翻成正面,按正面排序,如果要合法就是让两个互补的子序列的反面权值递减。那就考虑维护两个栈贪心一下就行了。

但是还要满足次数最少,而有的牌可以同时放进两个栈,就不会做了。

有个很巧妙的方式是我们以 $\min\limits_{j=1}^i{ a_j } > \max\limits_{j=i+1}^n{a_j} $ 的 \(i\) 把序列分成若干段,显然每一段互不影响可以单独算,而且每一段方案唯一。

  • CF720D Slalom

考虑 dp,设 \(f_{i,j}\)\((1,1)\)\((i,j)\) 的方案数

显然这样会算重,我们可以钦定如果两条路径的终点都在第 \(i\) 行上且两条路径被视作相同,我们只算更低的路径的方案数。

那么 \(f_{i,j}\) 就是 \((1,1)\)\((i,j)\)\((i,j)\) 是最低路径的方案数。

考虑扫描线,如果当前加入 \((l,r)\),那么就有转移 \(f_{i,r+1}=\sum f_{i-1,j}\),其中 \(j\)\((i-1,r+1)\) 一直往下走不遇到矩形能到的位置。

或许有人要问了,如果 \(r+1\) 被矩形覆盖了怎么办,那么这个矩形往上走的方案已经被前面的矩形算过了,我们不算就是了。

上面这个东西直接一个 set + 线段树就能轻松维护。

  • CF1601D Difficult Mountain

sol1 :如果 \(i\) 爬了山,山的高度必然 \(\ge \max(a_i,s_i)\),所以考虑按 \(\max (a_i,s_i)\) 排序,可以证明 \(\max\) 小的放在前面比放在后面更优。

sol2 :直接 dp,详情看代码

以下是感性理解:

\(f_i\)\([i,\inf]\) 段的答案,如果只有 \(a_i<s_i\) 的段,那么可以把这些段拿出来 dp,否则考虑 \(a_i\ge s_i\) 的段为当前转移 \([l,r]\) 带来的贡献。

如果 \([s_i,a_i]\)\([l,r]\) 无交,那么从 i 转移到 i-1 的时候稍微算一算就可以了,否则 \([s_i,a_i]\) 必须跨越 l 或 r,跨越 r 的直接算,跨越 l 的已经在 i 转移到 i-1 的时候算了。

  • CF618F Double Knapsack

盲猜答案肯定是一段区间,具体证明就是:

对于每个 \(sa_i\),求出最大的 \(\le sa_i\)\(sb_{j}\),那么 \(1\le sb_{j+1}-sa_i\le n\),而 \(i\)\(n+1\) 种,根据鸽巢原理必然有解。

为了保证 \(j\not= n\),如果有 \(sa_n \ge sb_n\) ,直接 swap(a,b) 就是了。

  • CF1129E Legendary Tree

如果以 1 为根,这个询问就可以问出集合内有多少点位于以 \(u\) 为根的子树内。

可以以此询问出每个点的子树大小,然后按子树大小从大到小排序,对于每个点,保证它的父亲在它的左边。

直接二分问儿子不太行,因为会有祖孙干扰询问,但是我们可以从右到左做,这样就保证祖孙找到父亲排除询问。

于是我们就可以直接二分了。

代码

  • CF1601E Phys Ed Online

由于一张票可以买很多次,所以每次用票必然是 l+xk 的地方用一次

答案就是 \(\min\limits_{}\{b_{l+k}\}+\min\limits_{}\{b_{l+k},b_{l+2k}\}+\ldots +\min\limits_{l+ki\le r}\{b_{l+ki}\}\),其中 \(b_i=\min\limits_{j=i-k+1}^i\{a_{j}\}\)

把询问离线下来,把 \(\mod k=i\) 的位置做一遍单调栈,然后用个数据结构去维护这个阿巴东西就行了。

代码

  • CF1601F Two Sorts

转化一下就是求 \((\sum (b_i-i) \mod {998244353})\mod 10^9+7\),其中 \(b_i\)\(i\) 的排名。

考虑 mitm,枚举每个串长度为 6 的无前导 \(0\) 前缀 \(val\),已知小于前缀的串数 \(c\),对于所有长度为 \(i\) 的后缀 \(x\),贡献即为 \((c-val\times 10^i)+(cnt_x-x)\),其中 \(cnt_x\) 表示 \(x\) 在所有长度为 6 的串中的排名(串中允许有前导0)

于是枚举前缀以及后缀长度,把加号左右两边的贡献看成 \(A\)\(B\),问题就变成有多少后缀能让 \(A+B \ge 998244353\),直接 lower_bound 即可。

至于 c 怎么求,可以按字典序枚举前缀,然后 c 就可以随便算了。

至于长度 < 6 的,或者前缀顶到 n 的边界的就直接爆搜

代码

  • CF1383C String Transformation 2

首先转化成图论,把字符 \(a\to b\) 的过程看成按时间顺序加边,问题变成若满足所有 \(a_i\to b_i\) 都有一条时间顺序递增路径,那么最少需要加多少条边。

这个东西看上去跟 DAG 有关系,答案也是 \(2n-m-c\),其中 \(m\) 是最大的 DAG 导出子图所包含的点数,\(c\) 是弱连通块的个数。

具体证明见 桂总博客另一篇博客

  • CF403E Two Rooted Trees

显然就是在链上 push_back 一个边的 id,可以直接树剖

然而树剖大多都是在重链的前缀 push_back,且每条边最多被删一次,于是我们考虑对每个重链维护一个指针,让这个指针一直往上爬,在爬的过程中删边,于是复杂度就降了一只 log。

  • CF1603D Artistic Partition

发现可分段数比较多的时候可以安排 \([1,1],[2,3],[4,7],[8,15]\ldots\) 以此类推,也就是说当 \(k\ge \lceil \log_2 n \rceil\) 的时候,答案为 \(n\)

然后考虑 dp,发现这个 dp 显然满足四边形不等式,具有单调性,直接做就行了。

  • CF533D Landmarks

考虑 \(i,j\) 中间放一个柱子,要怎么放才能合法。

由于要保证柱子不倒,我们就让柱子的高度为 \(\dfrac{x_j-x_i}{2}\)

首先我们预处理出 \(L_i,R_i\)\(L_i\) 表示 \(i\) 保留的情况下,左边能保留的最近柱,\(R_i\) 定义类似。

于是我们保证了 \(i\) 左边的柱子和 \(j\) 右边的柱子不倒,现在我们要保证 \(i,j\) 也不倒。

假设我们放柱子的位置为 \(x\),那么我们需要保证 \(x-x_{L_i}\ge 2\times d_i,x_{R_j}-x\ge 2\times d_j\)

稍微变换一下就是 \(x\in [x_{L_i}+2\times d_i,x_{R_j}-2\times d_j]\)

于是我们枚举 \(j\) 的位置,至于 \(i\) 则直接单调栈+二分即可。

  • CF1270F Awesome Substrings

可以对倍数根号分治,然后就没了。

  • CF1270H Number of Components

题意转换一下就是求满足 \(\min\limits_{j=1}^{i}\{a_j\} > \max\limits_{j=i+1}^{n}\{a_j\}\)\(i\) 的个数。

如果直接枚举 \(a_i\),把 \(<a_i\) 的看成是 \(0\),\(\ge a_i\) 的看成是 \(1\),那么就要满足序列中仅有一个 \(10\)

用线段树维护最小值的出现次数即可。

  • CF997E Good Subsegments

就是问 \(\max\limits_{i=l}^r\{a_i\}-\min\limits_{i=l}^r\{a_i\}=r-l\) 的子区间 \([l,r]\) 个数。

如果钦定端点 \(r\) 的话,由于 \(\max\limits_{i=l}^r\{a_i\}-\min\limits_{i=l}^r\{a_i\}-(r-l) \ge 0\),所以我们可以把问题转化为区间最小值出现次数。用线段树维护即可。

否则,问题转化为最小值的历史出现次数。

我们设一个 tag 储存未更新历史版本的次数,考虑如何 pushdown

由于子区间的每个版本的最小值随着大区间的修改而变化,所以我们仅需要考虑子区间是否包含大区间的最小值,如果包含则往下传版本次数。

有人可能会担心这样会不会把最小值不为 0 的情况给算进去,由于区间 \([1,n]\) 一开始的最小值就仅为 0,因此这样传递标记只会计算最小值为 0 的情况。

  • CF1603E A Perfect Problem

首先我们可以把序列排序(算方案可以直接 dp+组合数),这样判断只需要对区间判断。

然后我们需要满足 \(\forall l,r,a_l\times a_r \ge \sum\limits_{i=l}^r a_i\)

然后发现前缀显然比非前缀更难满足条件(证明显然),于是转化为对前缀判断,\(\forall i,a_1\times a_i \ge \sum\limits_{i=1}^i a_i\)

这个式子转一下就是 \((a_i-i)\times a_1 \ge \sum_{i=1}^i (a_i-a_1)\)

因为序列是排序过的,所以后面这项显然 \(\ge 0\),因此 \(a_i\ge i\)

如果 \(a_i =i\),则后面这项需要 \(=0\),也就是 \(a_1=a_2=\ldots=a_i=i\)

因此对于 \(i>a_1\) 的情况,\(a_i\ge i+1\) ,而其他情况无限制。

也因此,\(a_n=n+1\),也就要满足 \(a_1 \ge \sum_{i=1}^i (a_i-a_1)\),这必然是最强的限制,我们判断这个就行了。

我们设 \(b_i=a_i-a_1\)\(b_i\) 需要满足以下三条限制:

  • \(0\le b_i \le n+1-a_1\)

  • \(\sum b_i \le a_1\)

  • \(b_i\ge i+1-a_1\)

直接 dp 即可。

  • CF1254D Tree Queries

憨的做法:对度数根号分治,时间复杂度 \(\mathcal{O}(n\sqrt{n\log n})\)

牛的做法:树剖,对于重儿子直接子树加,至于轻儿子,则让询问点跳重链算即可。由于每个点往上的轻边只有 \(\mathcal{O}(\log n)\) 级别,所以复杂度为 \(\mathcal{O}(n\log n)\)

  • CF1418F Equal Product

如果 \(x_1y_1=x_2y_2\),那么有 \(a,b\) 满足 \(x_2=\dfrac{x_1}{a}\times b,y_2=\dfrac{y_1}{b}\times a\)

证明:设 \(g=\gcd(x_1,x_2),a=\dfrac{x_1}{g},b=\dfrac{x_2}{g}\)

那么第一个式子显然成立,第二个式子成立需要满足 \(y_1\mod b=0\)

$b=\dfrac{x_2}{g}\Rightarrow b \ | \ \dfrac{x_2y_2}{g}\Rightarrow b\ | \ \dfrac{x_1y_1}{g} $

也就有 \(\dfrac{x_1}{g} \times y_1 \equiv 0 \pmod b\)

由于 \(\gcd(\dfrac{x_1}{g},b)=1\),因此 \(y_1\mod b=0\)

于是我们可以枚举 \((x_1,a)\),相应的 \((y_1,b)\) 需要满足:

  • $\Bigl\lceil \dfrac{l}{x_1}\Bigr \rceil \le y_1\le \Bigl\lfloor \dfrac{r}{x_1}\Bigr \rfloor $

  • \(\dfrac{x_1}{a}\times b \le n\)

  • \(a<b\)

第一项可以双指针来维护,第三项可以用数据结构,第二项就是要让 \(b\) 最小,可以用 set

  • CF1599A Weights

如果是 LRLRLR....LR 的话显然可以直接排序,然后左右依次放即可。

如果不是的话,还是直接排序,考虑倒序操作,从插入变为删除,并且删除前要保证 L/R 的性质。

我们发现如果删除最小值,那么 L/R 不变,如果删除最大值,则 L/R 变化。

那么我们钦定第一次操作必然是选删除 \(n\),剩下的直接模拟即可。

  • CF1610F Mashtali: a Space Oddysey

结论:第一问的答案是边权为 \(1\) 的边的数量是奇数的点的个数。

如果只有边权为 \(1\) 的边,可以像 CF1499G 那样构造。否则,把图拆成两份,一份只有边权为 \(1\) 的边,另一份只有边权为 \(2\) 的边。

对于一个点 \(u\),如果只有 \(u_1/u_2\) 的度为奇数,那么直接连虚点,否则由于有 |入度-出度|=1 的限制,直接连 \((u_1,u_2)\)

然后直接欧拉回路即可。

  • CF833C Ever-Hungry Krakozyabra

发现答案是 1e6 级别的,直接 dfs 枚举答案,然后用类似数位 dp 的东西去 check 即可。

  • CF870F Paths

发现 \(dis(i,j)\le 3\),所以直接计数:

  • \(dis(i,j)=1\),即 \(\gcd(i,j)\not= 1\),可以直接用 \(\varphi\) 计数

  • \(dis(i,j)=2\) ,不好做,可以容斥

  • \(dis(i,j)=3\),设 \(i\) 的最小质因子为 \(p_i\),那么就是要数 \(\sum_{i,j}[ij>n][\max(i,j)\le n/2]\sum_{u,v} [p_u=i][p_v=j][u\bot v]\)

    发现如果满足 \(ij>n,p_u=i,p_v=j\) 的话那么必然有 \(u\bot v\) 。证明很显然。所以直接数就行了

  • \(dis(i,j)=0\),同上

  • CF1322D Reality Show

同 NOIP2021 T2,\(f_{i,S}\) 表示加入序列的最大数字 \(= i\),且数字合并后 \(2^{x-i}\) 的数字之和( \(x\) 为合并后大于等于 \(i\) 的数字)

转移分两种:

  • \(f_{i,S}=f_{i-1,S}+c_i-s_j\)

  • \(f_{i,S}=f_{i-1,S\times 2}\)

乍一看 \(n^3\),理智分析一下其实是 \(n^2\) 的:

由于第一种转移只影响 \(l_j=i\) 时的 \(f_i\),所以第二种转移可以直接从 \(l_j\) 开始,由于 \(S\) 不断除 2,所以上界也不断除 2,所以上界的总和是 \(\mathcal{O}(n)\)

  • CF1588D Strange LCS

考虑在第一个字符串上做子序列 dp,\(f_{i,S}\) 表示匹配到第 \(i\) 位,其他字符串匹配这一位的字母时用的是第一次出现的还是第二次出现的,记状态 \(S\)

然后直接 dp 就行了,写起来非常烦,code

  • CF1588E Eligible Segments

考虑怎么判断 \((i,j)\) 合法,就是所有点以自身为圆心画半径为 \(R\) 的圆, 线段 \((i,j)\) 与所有圆都有交。

首先考虑如何判断一个线段和圆是否有交。发现如果 \(i\) 对圆作两条切线,\(j\) 处在切线中,线段才可能与圆有交。然而线段可能在切线中而不在圆中,针对这种情况,我们 swap(i,j) 再判断一次即可。

两条切线形式化就是一段弧,问题转化为对所有弧求交,直接做就行了。

code

  • CF1613F Tree Coloring

就是要求 \(\prod_{i}(son_i-x)\),可以分治 NTT

但是有个更加牛的做法是把 \(son_i\) 从大到小排序,把相同的 \(son_i\) 合并,手动算出多项式,然后直接依次卷

复杂度是 \(\big(\sum_{k}[d_i\ge k]\big)\log n= \big(\sum_k d_k\big) \log n=n\log n\)

  • CF1588F Jumping Through the Array

直接对操作分块,设块长为 \(B\)

我们把块内每一个 2/3 操作影响到的点挑出来,划分成若干条链,形如下图:

链数显然是 \(\mathcal{O}(B)\) 级别的

对于 1 操作,我们预处理出 \(a_i\) 在块操作前的前缀和,至于块操作的影响,则对每条链记录增加的值 \(d_i\),枚举链并询问链中编号 \(\in[l,r]\) 的点数,可以二分,复杂度为 \(\mathcal{O}(B \log n)\)

对于 2 操作,我们直接暴力跳链维护 \(d_i\),复杂度是 \(\mathcal{O}(B)\)

对于 3 操作,直接 swap 就行了。

\(B=\sqrt{n}\) 复杂度就是 \(n\sqrt{n}\log n\) 的,然而由于 lower_bound 的常数极小,可以看为 \(\mathcal{O}(1)\),于是就过了。

code

  • CF765F Souvenirs

做法 1: 可以直接分块,散块对散块的贡献可以归并排序,其他就直接预处理

做法 2:可以离线,考虑 \(r\to r+1\) 的贡献,仅讨论顺序对的情况,我们把有用的 \(j\) 挑出来,发现只有 log 个(证明比较简单,懒得写),于是可以直接数据结构维护。

  • CF429E Points and Segments

转化成差分,让离散化后的 a 中不存在连续两个 1 或者连续两个 0

那么 ai 本身必然不能是 2 或者 -2,现在问题是给每个区间定向(定义红为正,蓝为反),然后对于每个点,每个方向的区间一样多。对于被覆盖奇数次的点,再加条虚边就行了。那么问题就转化为欧拉回路,直接做就行了。

感性证明:显然对于一个点 x 来说,如果 dfs 的过程中 u 到了 v(u<=x<=v),那么 v 如果想再覆盖 x 必须使用一条方向相反的边,两条覆盖的边正好抵消了。

  • CF889E Mod Mod Mod

\(f_{i,j}\) 为前 \(i\) 个数,\(X\bmod a_1\bmod a_2 \ldots \bmod a_i=x,x\in [0,j]\) 时答案表示成 \(ix+b\)\(b\) 的最大值。

那么考虑 \(f_i\) 如何转移到 \(f_{i+1}\)

  • \(j<a_{i+1}\)\(f_{i+1,j}=f_{i,j}\)

  • \(k\le j\bmod a_{i+1}\) : \(\small f_{i,j} \to f_{i+1,j\bmod a_{i+1}}\)

  • \(k > j\bmod a_{i+1}\) : \(\small f_{i,j} \to f_{i+1,a_{i+1}-1}\)

详情见代码

  • CF587F Duff is Mad

考虑暴力,就是在 trie 树上跳,然后算 ac 自动机上到根的和。

把上述过程根号分治一下就是 \(\mathcal{O}(n\sqrt{n\log n})\)

  • CF587D Duff in Mafia

可以 2-sat,每条边开两个节点 \(a_{i,0/1}\) 表示第 \(i\) 条边最后取没取。

对于匹配的限制,就是要求对于有同一个顶点的所有边,如果这条边选了另一条边就不能选,暴力连边 \(O(n^2)\),直接前缀连边 \(O(n)\)

其他限制也差不多,详情见代码

  • CF571D Campus

憨的做法:离线+kruskal重构树+线段树,一只 log

有点牛的做法:按秩合并并查集,由于只有 log 层所以可以在点上记录操作,然后点往祖先走维护操作,复杂度两只 log,但是在线

  • CF1456E XOR-ranges

考虑按位从大到小填数。

首先如果一个数没有上边界和下边界的限制,那么这个数等同于不存在。如果这个数在当前位有边界的限制,我们很容易就知道这个数在当前位到最高位的填法。

所以设状态 \(f_{d,l,r,0/1,0/1}\) 表示区间 \([l,r]\)\(l-1\)\(r+1\) 存在的最小代价,后面两个 \(0/1\) 表示贴的是上边界还是下边界。

然而【从第 d 位开始没有边界限制】,意味着【第 d 位填的数恰好是边界上的数的反转】,也就是说在这一位上填的数可能不与边界相同,所以我们再开两个 \(0/1\) 表示是否与边界相同即可。

具体看代码

  • CF1148H Holy Diver

往末尾加一个大小为 \(a\) 的数,我们可以找到 mex=a 的区间,然后在区间里找 \(a+1,a+2,a+3,\ldots\) ,直到找不到为止。根据这种方法,我们能维护每个点到 \(i\) 的 mex,而这些 mex 组成了一个阶梯状的图形。

mex=a 的区间中上升最大的一段可能和相邻一段相同,需要特判一下。

根据这种方法我们找到若干个五元组 \((k,a,b,c,d)\),表示 \(l\in [a,b],r\in [c,d]\) 时,\([l,r]\) 的 mex = k

由于 \([c,d]\) 不交,所以我们可以用 vector 来维护答案。

复杂度 \(\mathcal{O}(n\log n)\),具体细节看代码

  • CF455E Function

原题转化一下就是给定 \((l,r)\),求 \(\min\limits_{i+l-r\ge 0} \{s_r-s_i+(i+l-r)\times a_i\}\)

显然可以线段树套李超树,但还有一个很妙的单 log 做法

直接单调栈,显然如果 \(a_i\ge a_j,i<j\),那么 \(i\) 就是没用的。

然后如果一个数不在范围(即 \(i+l-r<0\)),那么由于这个数在单调栈内,是后缀最小值,它的负数贡献会被前缀和抵消掉,因此会比在范围内的数更劣。

于是我们只需要维护一个可撤销李超树即可,时间复杂度 \(\mathcal{O}(n\log n)\)

  • CF1091G New Year and the Factorisation Collaboration

显然除了 sqrt 外其他操作都没用。

考虑每次随机一个数字 \(x\),并询问 \(x^2\),得到一个数字 \(x'\)

\(x=x'\) 的概率为 \(2^{-c}\),其中 \(c=\sum\limits_{p\in \mathbb P} [n\bmod p=0][x\bmod p\not= 0]\),应该是比较低的。

\(x^2\equiv x'^2 \pmod n\) 可知,\((x+x')(x-x')\equiv 0\pmod n\)

因此,\(x+x'\)\(x-x'\) 的并集为 \(n\) 的质因子集合,我们称 \(x+x'\) 的集合为 \(S_1\)\(x-x'\) 的集合为 \(S_2\)

如果一个 \(p_i\) 能被单独分辨出,那么对于所有 \(j\) 来说,必然存在一个集合 \(S\) 使得 \(p_i\in S,p_j\not= S\)

由于 \(S_1,S_2\) 的质因数集合是随机的,因此进行 \(T\) 组询问后能分出每一个 \(p_i\) 的概率为 \((1-2^{-T})^{k^2}\)\(T=50\) 时概率极高。

至于如何分辨出 \(p_i\),每次把 \(n\)\(S\) 依次取 \(\gcd\)\(\gcd=1/0\) 时跳过,直到 \(n=1\)

详情看代码

  • CF521E Cycling City

答案形似于两个有交边的环,把这两个环扣出来就可以构造了

  • CF1608F MEX counting

\(f_{i,j}\) 为前 \(i\) 个数,当前的 mex 为 \(j\)

然后发现这样做会爆蛋,因为不知道前 \(i\) 个数中 \(>j\) 的数的状态

于是我们再加一维 \(k\) 表示有多少个 \(>j\) 的,我们并不知道状态,然而状态的主要目的是用来增加 mex,所以我们转移增加 mex 的时候用组合数计算合法状态数即可。复杂度 \(\mathcal{O}(n^2k)\)

  • CF1303F Number of Components

考虑枚举颜色 \(i\),统计其对答案的贡献,把修改操作 \(a_{x,y}=c\) 看作删除 \(a_{x,y}\) 并加入 \(c\),那么由于 \(c_i\) 递增,所以关于每个颜色 \(i\) 的操作在时间轴上是一段添加,后面跟着一段删除。添加可以用并查集维护,删除也可以倒着变成添加,也可以用并查集维护。

  • CF1430F Realistic Gameplay

贪心,\(f_i\) 表示第 \(i\) 波的第一天弹匣至少需要多少子弹,才能消灭之后全部怪物,由此来决定第 \(l_i-1\) 天换不换弹匣。

  • CF238D Tape Programming

发现跑 \([l,r]\) 的过程是 \([1,n]\) 过程中的一段,直接把这一段求出来然后求区间和,用前缀和即可。

  • CF1648E Air Reform

憨的做法:Boruvka 维护 MST,对于每个点 \(u\) 二分 Kruskal 生成树上的祖先,判断子树内是否有点 \(v\) 满足 \((u,v)\not \in E\)\(u\)\(v\) 不在 Boruvka 维护的同一个连通块内,复杂度 \(\mathcal{O}(n\log^3n)\)

套路做法:发现只需要找一个点,而如果我们把 Kruskal 生成树上的叶子用 dfs 序表示的话,那么点 \(v\) 显然是在 dfs 序上离 \(u\) 最近的。所以问题转化为带删除的 lower_bound,并查集实现即可。复杂度 \(\mathcal{O}(n\log^2n)\),如果使用 \(\mathcal{O}(1)\) lca 就是 \(\mathcal{O}(n\log n)\) 的。

  • CF1672H Zigu Zagu

对于字符串中相邻两个字符相同的位置,我们称其为颜色为该字符的空隙。我们发现,每次删除一个 01/10 交替的字符串,都能删除两个颜色不同的空隙,或者删除一个空隙。而若有颜色不同的空隙,就必然有操作能够删除两个颜色不同的空隙,所以答案就是 \(\max(\)颜色为 \(0\) 的空隙,颜色为 \(1\) 的空隙\()\),前缀和处理即可。

  • CF1667D Edge Elimination

因为一条边相邻的边数为偶数,所以这条边涉及到的两个点此时度数的奇偶性必然相同。

从叶子结点考虑,可以推出叶子结点的父亲如果要删除与叶子结点相连的边,该点的度数必然为奇数。而从叶子结点开始推,每个点 \(u\) 连向儿子的边可以知道在 \(deg_u\) 为奇/偶数时删除,而以此也可以推出 \(u\) 连向父亲的边删除时 \(deg_u\) 的奇偶性。

至于方案,构造比较简单,详情看代码

  • CF1515G Phoenix and Odometers

显然是求所有穿过 \(u\) 的环的 gcd ,然后仅保留 \(u\) 的强连通分量。

一个重要结论是如果有 \(A\to B\) 的长为 \(w\) 的路径,那么必然有 \(B\to A\) 的长为 \(-w\) 的路径,证明比较简单。

那么对于每条边都能建边权为负的反边,转换成无向图,对于每条返祖边算一算就行了,证明比较简单。

  • CF1552G A Serious Referee

考虑如何判断一个序列是否合法,枚举 \(x\),将 \(\le x\) 的设为 \(0\),否则为 \(1\),如果对于所有的 \(x\)\(01\) 序列合法,那么该序列合法。

询问所有的序列是否合法,问题就转化为判断所有 \(01\) 序列是否合法。

一个暴力做法是 \(\mathcal{O}(2^nk)\) 的。注意到操作是排序,也就是我们仅关心集合内有多少个 \(0/1\),在每个操作内枚举 \(1\) 的个数,复杂度是 \(\mathcal{O}((\frac{n+k}{k})^k)\)

用二进制实现就能达到这个复杂度,具体看 代码

  • CF1523F Favorite Game

有一个简单 dp 就是 \(f_{S,i,j}\) 表示传送门的状态为 \(S\),到达第 \(i\) 个地点(传送门/任务点),完成 \(j\) 个任务需要的最小时间。

然后发现在传送门时不需要记地点,在任务点时不需要记时间,于是直接做就行了,复杂度 \(\mathcal{O}(2^nm^2)\)

  • CF1268E Happy Cactus

如果是树可以倒着加边,然后设 \(f_u\) 为当前图上 \(u\) 能到达的点,就有 \(f_u=f_v=f_u+f_v\)

考虑仙人掌的情况,如果加边前两者不连通显然不会算重,否则该边就是环上的最小边,由于最大边的缘故,加最小边前环上最大边两边的点不能相互到达,因此这部分不会算重,但是两边的点经过最大边能到达的点会算重,减一下就行了,具体看代码

  • CF724F Uniformly Branched Trees

考虑有根树怎么做,满足不同构的要求可以让子树大小非递减来解决,设 \(f_{i,j,k}\) 为树中有 \(i\) 个点,其中第 \(i\) 个点的儿子数为 \(j\),最大子树大小 \(\le k\) 的方案数。转移就考虑枚举大小为 \(k\) 的子树数 \(l\),显然子树的方案数为 \(f_{k,d-1,k-1}\),由于需要满足不同构的要求所以方案数不是 \(\left(f_{k,d-1,k-1}\right)^l\) 而是 \(f_{k,d-1,k-1}+l-1\choose l\)

如果是无根树,满足不同构的要求可以钦定根是重心,然后奇偶分类讨论一下就无了。

  • CF1034D Intervals of Intervals

二分答案+HH的项链+颜色段均摊

  • CF1383E Strange Operation

考虑判断一个字符串是否能生成,首先这个字符串必须是原串的子序列,对于这个字符串的相邻字符,如果有 1 那么必然能生成,否则如果是全 0,那么这两个 0 之间不能有 1,也就是在以 1 划分的若干段 0 的极长段中,这两个 0 处于同一段。还有一个条件是如果原串不为全 0 段,那么该串也不能是全 0 段。

那么一个字符串就能被表示为 \(\{c_1,c_2,\ldots,c_k\}\),其中 \(k\) 为以 1 划分的极长 0 的段数,\(c_i\) 表示第 \(i\) 段中 0 的个数。由于会算重,所以钦定 dp 时的串是第一次出现的,前缀和优化即可做到 \(\mathcal{O}(n)\)

  • CF1286E Fedya the Potter Strikes Back

问题转化为,当前字符串为 \(s_{1\dots i}\),设其 border 集合为 \(S\),计算 \(\sum_{v\in S} \left(\min\limits_{l=i-v+1}^i\{w_i\}\right )\)

直接做是不可做的(把 border 集合中的 log 段等差数列求出来然后对等差数列求和...),可以考虑 kmp 的过程,继承 \(i-1\) 的 border 集合,然后将失配的 border 删除,在剩下的 border 中求出权值 \(\ge w_i\) 的并将其修改为 \(w_i\),前者复杂度与 kmp 相同,后者复杂度与单调栈相同,复杂度可以做到 \(\mathcal{O}(n)\)

  • CF1209G2 Into Blocks

一个 simple and navie 的想法是维护一个序列 \(p_i\),满足 \([p_{i-1}+1,p_i]\) 中出现的数都仅在该区间出现过,然后答案就是区间中出现次数最大值的和。实际上,对于每个数 \(i\) 与它们最左边的出现位置 \(L_i\) 和最右边的出现位置 \(R_i\),对 \([L_i,R_i]\) 区间加,\(p\) 就是区间加后值为 \(0\) 的位置序列。直接用线段树维护以上过程即可。

posted on 2021-12-16 10:26  exzang  阅读(264)  评论(0编辑  收藏  举报

导航