持续更新中……
CF504E. Misha and LCP on Tree
给出一棵
n(n\leq 3\times 10^5) 个点的树,m(m\leq 10^6) 次询问求树上两条链的 LCP 长度。
考虑和序列上的问题一样二分哈希。我们需要预处理从根到每个节点的子串和其反串的哈希值,还需要能快速求出 任意节点的
正解是树剖转化为序列问题然后后缀数组,可是我已经快忘了 SA 板子了。。
CF505E. Mr. Kitayuta vs. Bamboos
有
n(n\leq 10^5) 棵竹子,每天可以选k(k\leq 10) 棵竹子将其高度由h_i 变成\max(h_i-p,0) ,这天结束后左右竹子都会长高a_i 。求m(m\leq 5\times 10^3) 天后最高的竹子的最小高度。
看到求最大值的最小值,可以先考虑二分答案。
发现还是不很好做,于是就有了一个非常秒的操作就是 时 光 倒 流。
先把所有竹子的初始高度设为二分出来的
总结一下,这种思路可以用于处理一类“每次减少
CF506E. Mr. Kitayuta's Gift
求给定字符串
s(|s|\leq 200) 插入n(n\leq 10^9) 个字母后形成的不同回文串数,字符集为小写字母。
这题比较神仙。题意可以转化为求长度为
考虑从两边开始同时加入一个字符。先考虑
-
s_i=s_j\wedge i-j\leq 1 。此时再加入一个字符s_i 会达到匹配完成状态tar ,否则只会使步数+1 。\begin{gathered}{c}tar(k+1)\gets f(i,j,k)\\f(i,j,k+1)\gets 25f(i,j,k)\end{gathered} -
s_i=s_j\wedge i-j>1 。此时再加入一个字符s_i 会使左右两边匹配进度都增加一个字符,否则只会使步数+1 。\begin{gathered}{c}f(i+1,j-1,k+1)\gets f(i,j,k)\\f(i,j,k+1)\gets 25f(i,j,k)\end{gathered} -
s_i\neq s_j 。此时加入s_i 和s_j 分别会使左右两边匹配进度增加一个字符,否则只会使步数+1 。\begin{gathered}{c}f(i+1,j,k+1)\gets f(i,j,k)\\f(i,j-1,k+1)\gets f(i,j,k)\\f(i,j,k+1)\gets 24f(i,j,k)\end{gathered} tar 。此时怎么转移都可以。tar(k+1)\gets 26tar(k)
但这个 DP 的第三维是
实际上对于一条路径,它上面点的顺序其实是不重要的,我们可以把所有红点都安排在绿点前面。然后再造出来一条
然而还有
CF512D. Fox And Travelling
给出一张
n(n\leq 100) 个点的无向图,一个点可以被访问仅当它只有最多一个相邻节点没有被访问。对于所有k\in[0,n] ,求访问恰好k 个节点的方案数。
发现在环上的点无论如何都是遍历不到的,因此我们可以用类似拓扑排序的方法把不在环上的点分成若干棵树。这些树中有些是无根树,有些是有根树;有根树的根是这棵树中唯一与环相邻的点。对于有根树,我们可以一次树形 DP 求出答案:
直接做是
CF516D. Drazil and Morning Exercise
给出一个
n(n\leq 10^5) 个点的带边权树,令f_v 表示离节点v 最远的节点的节点与v 的距离。q(n\leq 50) 次询问求\{f_v\mid v\in S\} 极差不大于l 的最大连通块大小|S| 。
首先由直径的性质可知,树中与任意一点距离最远的一点一定是直径的两端点之一。于是我们可以三次 DFS 把
复杂度为
这题启示我们满足堆性质的树可以考虑按权值排成一条链,然后用双指针之类的操作来处理。
CF559E. Gerald and Path
数轴上有
n(n\leq 100) 条线段,对于每条线段给出它的长度和其中一个端点,求所有线段能覆盖的最大长度。
首先对所有线段按给出的端点位置排序,然后考虑 DP。令状态
黑色的表示已经计入贡献的线段,红色的表示新加入的线段。发现黑色中间的空隙是算不了的,所以这样会产生后效性。但是同时我们发现第二段黑色线段是没有任何用的,我们扔掉这种「没有用的线段」,加入时就只需要考虑
这里紫色的线段
这道题还存在
CF568E Longest Increasing Subsequence
给出一个长度为
n(n\leq 10^5) 的正整数序列A ,其中有k(k\leq 1000) 个位置空缺。给出m(k\leq m\leq 10^5) 个备选数字,要求在每个空缺位置填入一个备选数字,同一个数字不能重复使用。最大化最长上升子序列的长度,并输出方案。
因为要求严格递增,所以两个相同的数不会出现在同一个上升子序列中,因此我们可以暂时不考虑填数不能重复的限制。求 LIS 的长度可以常规做,考虑处理了一个前缀,记
g_i 表示长度为i 的上升子序列末尾元素取到f_i 时它的位置;l_i 表示以i 结尾的 LIS 长度;p_i 表示以i 结尾的 LIS 中i 的前一个元素。
这三个数组在转移的过程中都是可以轻易维护的。而构造方案就是要构造出一个 LIS,我们考虑从后往前做。首先我们通过
CF582E. Boolean Function
有八个布尔变量
A,B,C,D,a,b,c,d ,其中小写字母的值为对应大写字母取反。一个布尔表达式由上述布尔变量、&
和|
两个运算符以及括号组成。给出一个合法的布尔表达式s(|s|\leq 500) ,其中有些位置为?
表示可以为任意变量或运算符。再给出n(n\leq 16) 组A,B,C,D 固定时s 的取值,求补全?
的方案数。
发现整个表达式可以化成一棵二叉树,其中叶子节点是变量,而非叶子节点为运算符。考虑 DP,设 ?
则枚举所有情况相加。接下来考虑非叶子节点
其中 ?
则枚举两种情况加到一起。这个式子可以用 FWT 来快速转移,做到
CF585F Digits of Number Pi
给出长度为
n(n\leq 1000) 的数字串s 和长度为d(d\leq 50) 的数字串x,y ,求包含一个长度至少为\left\lfloor\dfrac{n}{2}\right\rfloor 的s 的子串的数字串t\in[x,y] 的个数。
这道题比较普遍的做法是对
题意可以转化为求与
现在考虑转移,即加入一个字符。可以尝试直接跳
CF587F. Duff is Mad
给出
n(n\leq 10^5) 个字符串s_1,\cdots,s_n(m=\sum_{i=1}^{n}|s_i|\leq 10^5) ,q(q\leq 10^5) 次询问s_l,s_{l+1},\cdots,s_r 在s_k 中的出现次数总和。
首先建出 AC 自动机。考虑每个询问都把
接下来考虑长度
关于
CF590E. Birthday
给出
n(n\leq 750) 个只包含a,b 的两两不同的字符串s_1,\cdots,s_n(m=\sum_{i=1}^{n}|s_i|\leq 10^7) 。你需要去掉一些字符串,使得在剩下的串中,没有一个串是另一个串的子串。使保留的串的个数尽可能多,并输出方案。
考虑建出一张图,证明不会
但是总串长很大,如果直接 AC 自动机上暴力跳
总复杂度为
CF594E. Cutting the Line
给出字符串
s(|s|\leq 5\times 10^6) 和一个正整数k(k\leq |s|) ,要求把s 分为至多k 段,每段翻转或不翻转,使得变换后s 字典序最小。
这可能是我做过的思维难度最大的一道字符串了。。正确性需要证明的地方很多,请结合感性食用。
前置知识
- Lyndon 分解
- 最小表示法
- 扩展 KMP
符号约定
n=|s| 。s' 表示s 的反串。s[i] 表示字符串s 的第i 个字符,s[:i],s[i:] 表示以i 为端点的前缀或后缀。uv 表示u 与v 顺次拼接,s^k 表示s 重复k 次。
解题分以下几种情况讨论:
k=1
这种情况直接特判掉,
k\geq 3
先考虑
-
引理:一个字符串最小后缀出现的位置不相交
证明:假设最小后缀出现的位置相交,那么相交部分一定是 Border,所以它会是一个更小的后缀,矛盾。
因此我们可以每次从
如果
- 两个 Lyndon 串相等。此时分别提取和同时提取这两个串都是一样的,不需要解释。
- 两个 Lyndon 串都是回文串。此时同时提取这两个串,然后翻转一次,与分别提取两个串是一样的。别忘了原问题中字符串还可以翻转。
可以证明其他情况都不能合并了,否则答案会变劣。实现其实很容易,第一种情况在做 Lyndon 分解时就可以把相同的串合并到一起,而第二种易知回文 Lyndon 串只可能是单个字符(否则最后一个字符才是最小后缀)。所以直接比一比长度就可以了,于是我们在线性时间内将问题转化为了
k=2
设将
对于分割出来的两个串,枚举它们翻转 / 不翻转,可以分为四种情况讨论:
1. t_1,t_2 都翻转
此时答案就是
2. t_1,t_2 都不翻转
枚举分割点,答案就是
3. t_1 翻转,t_2 不翻转
从后往前枚举分割点,设
如图,红色有向线段表示之前的最优串,紫色有向线段表示当前串。我们要比较这两个串的字典序,需要询问两个绿色串间和两个蓝色串间的 LCP。随便推一下,发现绿色的 LCP 等于
4. t_1 不翻转,t_2 翻转
设
-
定理 1:最终答案一定满足存在
i ,使得t_1=B_i 。证明:若最优答案在
b_i 的内部,因为b_i 由相等的 Lyndon 串组成,所以将分界线移到b_i 前一定更优。 -
定理 2:
B_i>B_{i+1} 。证明:取
a_i 为B_i 的第一个 Lyndon 串。假设a_i\leq B_{i+1} ,则B_{i+1} 的每个前缀都不小于a_i ,也就是说不能划分出比a_i 更小的 Lyndon 串了,矛盾。因此B_i>a_{i+1}>B_{i+1} 。由 定理 2 可知,除非
B_{i+1} 是B_i 的前缀,否则t_1=B_i 一定比t_1=B_{i+1} 优。取最后一个B_p 不是B_{p-1} 前缀的p ,那么答案t_1=B_i 一定满足i\geq p 。 -
定理 3:若
B_{i+1} 是B_i 的前缀,则一定有|b_i|< |B_{i+1}| 。证明:假设
|b_i|\geq |B_{i+1}| ,则b_i 会在B_{i+1} 的前缀中出现,而b_i=a_i^k ,矛盾。因此原命题得证。推论:
|B_{i+1}|<\dfrac{1}{2}|B_i|(i\geq p) (显然)由推论可知
m-p=O(\log n) ,因此可以枚举这些断点,然后二分哈希比较,这样就可以做到O(\log^2 n) 的复杂度。
虽然好像做完了,但这个哈希的做法还是不够优美。我们可以继续分析性质。
假设
于是,我们只需要找到最大的 并且没有用到哈希和任何高级字符串数据结构
CF611H. New Year and Forgotten Tree
有一棵
n(n\leq 2\times10^5) 个节点的数,给出它n-1 条边的两个端点在十进制下的位数,要求复原每条边,或判断无解。
将节点编号按十进制下的位数分类,显然只有
因为
除了读入和输出,复杂度仅与
CF613E. Puzzle Lover
给出一个
2\times n(n\leq 2000) 的小写字母矩阵A 和长度为m(m\leq 2000) 的模式串s 。求矩阵中有多少条路径满足:
- 起点和终点为矩阵中任意两个不同的位置;
- 只能向上下左右四个方向走,且不能多次经过同一个位置;
- 经过的字符顺次连接起来恰好是
s 。答案对
10^9+7 取模。
考虑使用 DP 处理字符串匹配问题。发现不好处理「折返」的情况,但这种情况只会出现在路径的起始和结尾部分,如图:
上图中紫色线段把红色的路径划分成了从左到右的三部分。设
复杂度
CF643F. Bears and Juice
有
n(n\leq 10^9) 只熊和若干个桶,有恰好一个桶里装酒。每天每只熊会选一些酒桶查看,如果选的桶里是酒那么这只熊就会睡觉并不会回来。通过这个信息,熊们想知道哪个桶里是酒。如果前i 天睡觉的熊的数量不超过p(p\leq 130) ,且第i 天至少有一只熊没有睡觉,它能根据前面的信息推算出藏酒的桶,那么就成功了,否则失败。对于所有的i\in[1,q](q\leq 2\times 10^6) ,求在确保能成功的情况下,最多可以放多少个桶。你只需输出每天的答案乘i 模2^{32} 后的异或和。
首先可以发现一只熊只有第一次喝某个桶的饮料是有意义的,因为如果这一桶是酒就醉了,不是的话再喝也没用,所以可以认为一只熊只会喝一桶饮料一次。我们来分析一下,熊们得到的所有「信息」就是:对于一只熊,它有没有睡觉,如果睡了是在第几天。假设有两个桶,喝它们的熊的集合都相同并且时间也相同,那么如果其中有一桶是酒,剩下的熊就无法分辨,于是会失败。我们对每个桶画一张表格,第
- 有
1 的列的数量不超过\min\{p,n-1\} ,即存在对喝这桶饮料的熊的数量限制。否则万一这桶是酒,就会失败。 - 每列最多只有一个
1 。因为每只熊只能第一次喝这桶饮料一次。
枚举有
组合数表示枚举有
有一个小问题就是组合数的求法。这道题的模数是
CF666E. Forensic Examination
给出字符串
s(|s|\leq 5\times 10^5) 和m 个总长不超过5\times 10^4 的字符串t_1,\cdots,t_m 。q(q\leq 5\times 10^5) 次询问,每次给出L,R,l,r ,求s[l\cdots r] 在t_L,t_{L+1},\cdots t_{R} 中哪个串里出现次数最多,并输出次数。如果有解输出最靠前的。
下面是一个在线做法。
对所有
思路不难,但我没怎么写过广义 SAM 线段树合并的板子,所以踩了一堆坑。在这里提示一下广义 SAM 和普通 SAM 的区别:
- 普通 SAM 转移数为线性(
O(|s|) ),而广义 SAM 的转移数则是 Trie 树大小再乘上一个字符集(O(|T|\cdot|A|) )。 - 广义 SAM 最标准的建立方式是 Trie 树 BFS,但用得比较多的是在线做法。思路是逐个插入串,但与普通 SAM 的插入方法略有不同(并不是直接把
last 设为root )。其实就是多了两个特判,具体可以看 这篇博客。虽然该博客的做法还是可能会建出多余节点,但一般不会影响到正确性,所以我们在给出所有串的时候通常采用这种方法。 - 由于一些原因,广义 SAM 可能存在某节点与其
parent 树上父亲的len 相等的情况。所以合并信息时不能直接基排,最好是把树建出来 DFS。
本题除了这种方法,xht 还有一篇后缀数组的题解,我觉得思路也不错,在这里写一下:
- 将
s 和t_1,\cdots,t_m 用分隔符隔开后合并成一个字符串s' ,求出这个串的后缀数组以及height 数组; - 若
s[l\cdots r] 在s' 的某个位置出现了,说明s[l] 与这个位置的 LCP 不小于r-l+1 。这在后缀数组中体现为sa_l 左右的height 不小于r-l+1 的一段区间。那么我们将height 从大到小合并,建出 Kruskal 重构树(其实这里也就是笛卡尔树)。 - 询问时的一个区间就是一棵子树。可以倍增来定位这棵子树的根,然后就是要求子树中值在
[L,R] 内的众数。这也是可以用线段树合并来维护的。
以上两种做法其实是异曲同工的,视
CF671D. Roads in Yusland
给出一棵
n(n\leq 3\times 10^5) 个点以1 为根的树,有m(m\leq 3\times 10^5) 条路经(x_i,y_i) ,保证y_i 是x_i 的祖先。每条路径都有一个代价c_i 。要求选出若干条路径覆盖树上的每一条边,使总代价最小。
考虑 DP,设
因为转移时总代价会变化,所以要支持左偏树上全局加法,可以用标记维护。查询根节点时,若
这道题还有一个解法是利用线性规划的对偶性。可以证明这道题与下面的问题对偶(还不会证):
给每条边标记一个权值,使得每条路径上的权值和不超过这条路径的权值,求树上所有边的最大总权值。
显然我们可以贪心地尽可能把权值赋给靠下的边,于是直接从下到上用可并堆维护
CF698D. Limak and Shooting Points
平面上有
k(k\leq 7) 个石头发射点和n(n\leq 1000) 个怪物,每块石头会击中它路径上第一个怪物并和这个怪物同时消失。求按某种方式打出所有石块后可能被击中的怪物数。
考虑枚举每个怪物,然后再枚举使用石头的顺序,判断这个怪物有没有可能被打到。具体地,设使用石头的顺序为
这个做法似乎可能有两个问题:
-
对于某一种使用石头的顺序,上面钦定的依次打不是最优的。
确实可能会出现这种情况,但因为这个钦定的顺序实际上是对原顺序的一种置换,所以这时一定存在另一种顺序使得钦定的为最优。也就是说,这么枚举是补充不漏的。
-
目标的怪物成环。
这种情况其实和上面一样,也肯定不是最优的(最优解当然每个怪物只会打一次)。换句话说,一定存在一组最优解使得目标怪物不成环。
所以这种做法的正确性得到了保障。
CF700E. Cool Slogans
给定一个字符串
S(|S|\leq 2\times 10^5) ,要求构造S 的子串s_1,\cdots,s_k ,使得\forall i\in[2,n] ,s_i 在s_{i-1} 中出现了至少两次。求最大可能的k 值。
这个题涉及到两个重要的结论,不是很好推。
-
一定存在一组最优解,满足
\forall i\in[2,k] ,s_i 是s_{i-1} 的后缀。假设
s_i 不是s_{i-1} 的后缀。那么我们把s_i 在s_{i-1} 中最后一次出现位置后面的字符在s_{i-1} 中都删掉,这样显然不会影响s_i 在s_{i-1} 中的匹配,而且s_{i-1} 变短了有利于更前面的匹配,所以答案不会变劣。 -
对原串建出后缀自动机后,我们可以贪心地以一个状态中的最长子串来代表这个状态。
感性理解一下,假设对于 right 集合里的某个位置,一个状态代表的两个子串中有一个可以与最长串匹配而另一个不能匹配,那么不能匹配的串就会出现在另一个状态里,矛盾。所以选最长子串表示这个状态是没有问题的。这个也可以当个结论记。
也就是说,一定有以组最优解可以表示成 parent 树上某个点的某些祖先节点。考虑树上 DP,设
g_{fail_i} 在i 中出现了不少于两次。此时fail_i 也会在i 中出现至少两次,f_i\gets f_{fail_i}+1,g_i\gets i 。(这里我还没有搞清楚)g_{fail_i} 在i 中出现了不到两次。此时保持和父亲相同即可,f_i\gets f_{fail_i},g_i\gets g_{fail_i} 。
CF704B. Ant Man
- 有
n 个元素,第i 个元素有五个参数x_i,a_i,b_i,c_i,d_i 。- 你需要求出一个
1 \sim n 的排列p ,满足p_1 = s, p_n = e ,同时最小化这个排列的权值。- 一个排列的权值为
\sum_{i=1}^{n-1} f(p_i, p_{i+1}) ,其中f(i,j) 的值有两种情况:
- 若
j < i ,则f(i,j) = |x_i - x_j| + c_i + b_j 。- 若
j > i ,则f(i,j) = |x_i - x_j| + d_i + a_j 。n \le 5 \times 10^3 ,1 \le x_i,a_i,b_i,c_i,d_i \le 10^9 。题意由 xht37 翻译。
考虑把一个点的贡献拆成左右两边,这个贡献与两边点权值的相对大小有关。我们从小到达插入每个点,那么每个点插入时的贡献是确定的,因为两边点都比它小。此外,它还会把一个点的某一侧由原来比这个点小修改成比它大。这和它插入的位置有关,而与它插入的时间无关。所以每次可以贪心找一个代价最小的位置插入,这里的代价是指答案的增量。可以暴力维护一条链表做到
CF704C Black Widow
给出
m(m\leq 10^5) 个布尔变量x_1,x_2,\cdots,x_m ,令x_{-i}=\neg x_i 。再给出n(n\leq 10^5) 个形如x_i 或者x_i\vee x_j 的表达式,保证每个变量在所有表达式中出现从次数不超过2 。求所有变量的2^m 种取值中所有表达式的异或和为1 的方案数,对10^9+7 取模。
注意到「每个变量的出现次数不超过
-
孤立点。这个表达式
i 可以有四种形态:- 形如
x_i 。此时c_0=c_1=1 。 - 形如
x_i\vee x_j(i\neq j) 。此时c_0=1,c_1=3 。 - 形如
x_i\vee x_i 。此时c_0=c_1=1 。 - 形如
x_i\vee x_{-i} 。此时c_0=0,c_1=2 。
- 形如
-
链。因为链上的问题处理起来没有后效性,考虑 DP。设
f(i,0/1,0/1) 表示处理了这条链上前i 个表达式,i 之前所有表达式的异或值,以及i 前面变量的取值。转移考虑旧的异或值,以及i-1 和i 前的变量的取值,一共是8 种情况,别忘了考虑下标正负的影响。但这并没有结束,我们还没设定起始状态和目标状态。这两者是和链首与链尾的情况相关的。具体地,链首节点有两种情况:
- 形如
x_i\vee x_j(i\neq j) 。此时链首表达式前的变量可以赋任意值,那么初始状态为f(0,0,0)=f(0,0,1)=1 。 - 形如
x_i 。此时链首表达式前没有变量,不过我们可以钦定它为0 。那么初始状态为f(0,0,0)=1 。
对于链尾,可以同样处理。
- 形如
- 环。考虑随便切开一个位置,这样环就变成了一条链。枚举切开位置变量的取值,分别钦定链首前和链尾后的变量同时为
0 或1 ,然后跑两次链上 DP 即可。
最后要注意,如果一个变量在所有表达式中都没有出现,那么这个变量对答案有
细节很多,实现很复杂的一道题。
CF704D. Captain America
平面上有
n(n\leq 10^5) 个点,要把每个点染成红色或蓝色,代价分别为r,b 。给出m(m\leq 10^5) 个限制,每个限制要求在一条平行于x 轴或y 轴的直线上的蓝点与红点数量差的绝对值不小于d_i 。求染色的最小代价以及方案。
将行和列看成点,对于每个点,在其离散化后的横纵坐标之间连边,这样就建出了一个二分图。不妨设
因为二分图上的 Dinic 算法复杂度为
CF708D. Incorrect Flow
给出一个
n(n\leq 100) 个点m(m\leq 100) 条边的可能错误的网络流,即可能会出现流量不守恒或流量大于容量的情况。每次操作可以把c 或f 加一或减一,求使这个流正确的最小操作次数。
这道题可以转化为一个有源汇上下界最小费用可行流问题。
建图考虑原图的每一条边
c\geq f :连边(v,u,0,f,1),(u,v,0,c-f,1),(u,v,0,\infty,2) 分别表示减小f 、增大f 但不超过c ,同时增大c,f 这三种情况。c<f :先把答案加上f-c ,因为这是必然会产生的代价。然后连边(v,u,0,c,1),(v,u,0,f-c,0),(u,v,0,\infty,2) ,分别表示同时减小c,f ,减小f 但不低于c ,同时增大c,f 三种情况。
这个建图符合费用递增模型,所以它有正确性保证。然后跑板子就可以了。