五一集训 杂题练习
文章目录
Mole Tunnels
有一棵个点完全二叉树,的父亲是。有个球,分别位于号结点。同时,每一个结点有一个容量,表示可以容纳的球的个数。如果一个点容纳不下了,就要把多于的球移动到其他点去。
对于所有,询问前个球要放到结点且不超过容量的的最小移动的总步数。
,保证有合法方案。
费用流 细节
容易想到费用流。由于树高是的,因此我们可以暴力模拟増广的过程。每次増广的路径一定是先向上后向下的,因此记录表示结点子树里费用最小的能到达汇点的流。増广的时候可以暴力増广,更新。
时间复杂度。
Addition and Subtraction Hard
给你一个只有加法和减法的表达式,你需要向里面加括号,使得表达式的值最大。
。
贪心
左括号一定在减号后面。第一个左括号后的一些加都会变成减,其他可以变成绝对值的形式。例如
可以变成
枚举左括号找最小即可。
时间复杂度。
K-th K
给定长度为 n 的序列,求一个长度为的序列,其中每个数都出现了次,要求满足第个在第个位置。构造可行解或输出无解。
。
贪心
每个位置都尽可能的选择在之前还没满个的最小的即可。
时间复杂度或者。
Yet Another String Matching Problem
给定两个字符串,字符集为,每次操作任选两个字符,可以将和中的所有替换成。对中每一个长度为的子串,求最小操作次数使得它们相等。
。
去你妈的 多项式
我们要 KMP
对于两个等长字符串,考虑求出让它们相等的操作次数。如果,我们就把字符和连边。那么答案就是减去连通块的数量。
那么我们设表示字符在和上是否连边。那么可以一波 NTT 猛如虎。
然而我们不要用这个憨批做法。
考虑枚举字符集的子集。设,。那么如果和匹配,说明这个子集没有向外连出的边,也就是说这个子集恰好包含了若干个连通块。而满足这个条件的子集恰好是 2 的连通块个数次方。因此求出了匹配的数量就可以快速算出连通块个数。匹配就直接 KMP 就行了。
时间复杂度。
树上的最短路
给出一棵个点边带权的树,树边是无向边。有个五元组表示对于路径上的任意结点和上的任意结点,都有从到权值为的无向边。
给出一个点,求从出发到所有点的单源最短路。
。
算法一
树链剖分,每条路径可以拆成个点。对于一个五元组,建立一个中间点,可以建条边。总边数是。使用 Dijkstra 算法,时间复杂度。
算法二
考虑 Dijkstra 的一个变种算法。我们在堆里同时存点和边。对于一个点我们存到达这个点的最短路,对于一条(有向)边我们存到达它起点的最短路加上它的长度。每次取出堆顶:
- 如果是一个点,那么它所有邻边的最短路就确定了,把它的邻边放进堆里(如果这些邻边之前没有被访问过)。
- 如果是一条边,那么它的终点的最短路就确定了,把它的终点放进堆里(如果这个点之前没有被访问过)。
这样我们发现,每个点和每条边最多被更新一次。
那么我们算法的复杂度下界就变成了总点数()。
接下来我们优化 Dijkstra 的过程。如果说我们能把一个五元组用一个对象来代替(算法一使用了个对象),那么总的对象数(边数)就变成了,则 Dijkstra 的堆操作复杂度就优化成了。也就是说,Djikstra 的堆里存两类对象:
- 边的集合:也就是一个五元组。可以更新它到达的点集的最短路。所谓到达的点集,就是路径上的点。
- 结点:可以更新包含它作为起点的五元组(边集)的最短路。
接下来考虑具体的更新方法。
如果堆顶是一个五元组,那么我们就要找到路径上所有还未被访问过的点。这个可以并查集维护。这部分的均摊复杂度是。
如果堆顶是一个结点,我们就要找到所有包含作为起点的,还未被访问过的五元组,即所有被包含在路径的五元组。而包含的路径有两种情况:
- 一个端点在子树内,一个端点在子树外。
- 是两个端点的 LCA。
第二种情况可以每个点开一个 vector 维护。
对于第一种情况,我们预处理整颗树的 DFS 序,那么子树的 DFS 序是一段连续的区间。考虑一个小根堆序列,其中表示满足或的五元组集合。它的优先级是:另一个端点的 DFS 序越小,优先级越大。那么对于的子树,假设它对应的区间是,我们就查询里的最小值。如果最小值的端点在的子树外,就更新它,然后从堆中删除它。
类似地,维护一个大根堆序列来处理最大值。每一个五元组至多被删除两次(两个序列里各一次),因此均摊复杂度仍是。
算法总复杂度。
修订记录
- 2021年2月11日 第2次修订
- 2020年6月12日 创建文章