本文主要讲解一些近期遇到的一些有启发意义的 Codeforces 题目。不定时更新。

Anu Has a Function

定义

给你一个长度为的序列,你可以随意安排顺序,最小化

摘要:理解位运算。

容易发现。相当于在中把属于的部分挖掉。

因此的值只和的值有关。

把复杂度做到即可。

代码

Aerodynamic

给你一个凸多边形

定义凸多边形函数

  1. 随便固定一个点
  2. 在保证(即在的边界或内部)的情况下随便平移,尽可能经过多的点(覆盖多的面积)。所经过的点的集合构成多边形

是否相似。

摘要:大力猜结论。

如果是正三角形的话,就是正六边形。

容易发现,当是奇数时条边,与不相似。

为了不产生多余的边,就要求的对边平行且相等(第条边和第条边平行且相等)。感性理解不难。

大力猜想这是重要条件。

复杂度

代码

Water Balance

给你一个长度为的序列。每次你可以把的元素都变成(变成平均数)。

问能操作出的字典序最小的序列是啥。

摘要:贪心,复杂度均摊。

由于是字典序最小,因此我们从前往后依次考虑。

如果就不管。

如果,显然我们一定会以为左端点做一次操作。但是这次操作的区间有多长?我们可以一直向右延伸,如果平均值变小就延伸,如果变大就停止延伸,然后把这段区间给操作一次。

操作完之后,我们还可以找到,如果,就把左端点往左延伸一点然后进行一次操作。毕竟我们要求字典序最小。直到不存在的情况位置。

然后我们跳过这一段区间做后面的事。

但事实上这么做了一轮之后不一定字典序就最小了。还可以做第二轮第三轮。

可以使用链表缩点优化。

稍作感知,认为做的次数不会很多。

代码

Animal Observation

题面较长。但样例的图十分可读。

摘要:DP 优化。

表示前行,其中第行选择从第列开始的矩形(占据两行)的最大值。

转移。

转移。根据的关系可以分类讨论。

容易发现,使用前缀,后缀和单调队列就可以分别优化了。

时间复杂度

代码

Cow and Fields

给你一个个点条边的无向简单图。有个关键点。要求你必须在个关键点中选择两个点连一条边。

最大化的最短路。

摘要:转化为数学模型。

表示的最短路,表示的最短路。

对于两个关键点,如果加入并强制走这条边,则最短路是

因此我们要求的是

不妨设,即,则我们要求的是

可以前缀后缀的时间统计出来(算上了排序的时间)

然后再和比较一下即可。

时间复杂度

代码

Cow and Treats

题面较长

摘要:观察,分析,发现左边和右边不能相交。于是枚举分割位置然后计算。

观察发现:

  1. 同一种颜色(sweetness)最多选 2 头牛(分别从左右两个方向出发)。
  2. 左边走的最远的牛和右边走的最远的牛不能碰面。
  3. 一但安排好了两个集合,只要满足上面两个条件,那么一定可以按要求使得所有牛都睡觉。

于是我们枚举左边的牛走的最远的走到哪里。然后对每个颜色统计放的最多的方案数并更新答案即可。

代码

Cow and Vacation

给一个个点的树,有个休息点(关键点)。你在不休息的情况下最多连续走条边。你走到一个休息点后就可以休息好,继续走最多条边。次询问,能否从走到

摘要:两边 BFS,并查集。

一开始想了一个虚树 + 并查集 + 点分治的思路,难想又难写。所以就不讲了。

基本的思路是:我们把距离休息点以内的点和休息点 merge。那么如果两个休息点距离小于等于,他们就会 merge 到一起。询问的时候先判距离以及是否在同一个集合。否则就相向而行各走步。如果走到这里了都不能走到一个集合里,说明不行(注意,我们是把距离休息点以内的点和休息点 merge 过的,因此如果走步后不能走到一个休息点上,就说明不行)。

merge 就用并查集做。我们事先把每条边中间加一个二度点(距离乘),这样就不用考虑的奇偶性了。然后走步的时候相当于倍增跳祖先。

时间复杂度

代码

Reachable Strings

对于一个 01 串你可以进行以下两种操作:

  1. 选择一个110并将其替换为011
  2. 选择一个011并将其替换为110

给你一个串,有次询问,问你能否通过若干次操作变成

摘要:根据一段 1 个数的奇偶性给 0 分段。然后做字符串匹配(哈希或者 SA)。

上面的操作可以理解为是,一段偶数个 1 可以随意穿梭在 0 之中。因此我们把连续的偶数个 1 可以直接删掉。那么就剩下了一个 01 串使得每一段连续的 1 只有一个 1。

那么我们把每段 0 的个数写成一个序列,这就等价于问你两个序列是否相等。

可以使用 SA 或者哈希计算。

时间复杂度

考场上抽风,写了一个线段树 + 哈希,最后还没交上去,不知道在想啥。

代码 仅供对拍,不建议学习。

Treeland and Viruses

题面较长。

摘要:建虚树,跑多源最短路。

注意,最短路以到达时间(不是路程)为第一关键字,病毒编号为第二关键字。

代码

Kuroni and the Score Distribution

给出。构造长度为的序列满足:

摘要:构造。

当时做这题时,读错题了,以为是求构造的方案数。把我自闭了半小时。

首先思考,如何构造使得最大化?构造即可。

因此我们依次构造,让的数量接近。然后把下一个数字稍微改一下使得刚好凑出。然后我们要求剩下的数字不能有任何的情况出现。那么构造即可。乘的原因是避免与前面构造的产生

无解的情况稍微判一下。

代码

Kuroni and the Punishment

给出长度为的序列,要求你构造长度为正整数序列使得,且最小化

求出这个最小化的

摘要:乱搞。

如果确定了,那么我们可以求出最小的

,易得。因此若一定是某个的约数。同时易证,存在是质数(质因子)的最优解。

好接下来开始乱搞。我们的大致思路是随机几个质数出来更新答案。但是不能乱随。

由于,因此我们就随机几个,把的质因子都拿出来更新答案。

可以证明,错误的概率是指数级减小的()。

要去重后再更新。

代码

Kuroni and Antihype

个数和一个集合。你可以进行两种操作:

  1. )加入,没有奖励;
  2. 选择中的一个数和不在中的一个数,且,把加入,奖励为

要求你把都加入到中,求出最大化的奖励的和。

,一开始中有。那么所有的 1 操作可以转化为的 2 操作。

容易发现,所有的 2 操作构成一个以为根的有根树。

设树上结点的度为。那么我们的奖励显然为

注意到

考虑最大化。这等价于加权无向图

中的最大生成树的边权和(注意,这和上文中的有根树没有任何关系,因为我们已经把问题转化为最大化了)。

考虑使用 Boruvka 算法 求最大生成树。

那么我们的问题转化为,如何求与相邻的权值最大的边不在同一连通块。可以使用子集前缀和解决,记表示满足最大的表示次大的,记作,且不在同一连通块。这个可以 FMT 求出。然后我们就可以求出与相邻的权值最大的边了。

时间复杂度,其中,表示值域。

代码