Codeforces 题目选讲 2
文章目录
Present
给出长度为的序列,求
。
摘要:逐位计算。
考虑按位计算答案。考虑计算答案的二进制第位是否为(从计数)。由于高于的位不影响第位的数,不妨设。因此。那么我们要计算的就是
的奇偶性。
不妨将排序。枚举,在序列上二分查找即可。
时间复杂度。
可以使用双指针 + 归并排序优化到。
Instant Noodles
给你一个个点的二分图,左部右部各个点。有条边。右部的点点权为。
定义表示左部点集的邻居集合(显然都是右部的点)定义表示中的点的点权和。
求。
。
摘要:哈希判邻居集合是否相等。
由于是和的 GCD,因此我们关系的是:对于两个右部点,他们是否同步出现(要么同时出现,要么同时不出现)。
如果两个点同步出现,那么我们就只用考虑它们的和。
推广之。若右部点集合中的点均同步出现,则我们只用考虑的点权和。
因此答案就是所有同步点集合的点权和的 GCD。
要判断右部点两个点是否同步出现,只需要判断它们的邻居集合是否相同即可。
若两个点的邻居集合不同,那么一定存在一个左部点集合使得这两个点没有同步出现。
使用哈希,时间复杂度。
Reality Show
给出长度为的序列和,给出一个长度为的序列。
你可以构造一个长度为的序列满足:
- (单增);
- (非严格单减)。
然后你需要对和一个集合做这样的操作:以的顺序考虑:
- 你会获得的奖励;
- 若,把加入并结束这次操作;否则把从中删除,并令。
你的得分是奖励之和减去。
请构造满足条件的并最大化得分。输出得分。
。
摘要:倒序 DP。
首先注意到在第二步操作的时候,你以任意顺序操作,得分不变。
而我们操作的过程实际上可以看做是二进制的进位过程。
那么我们考虑倒着构造。那么我们每次构造的就是当前序列中最大的元素。
考虑 DP。设表示最大值为,且的人有个时的最大得分。
若我们在的开头插入(即新的),那么就可以对做一次背包:
另一方面,在的时候可以进位到。但是不是所有都需要进位。因为我们只改变了,因此只需要对的部分进位即可。另一个事情是,会贡献到,则的范围每次除以 2。因此 DP 转移的复杂度是的。
总复杂度。
AND Segments
给出和个限制。问有多少长度为的序列满足
- ;
- ;
。
按位考虑。限制转化为,一段区间全 1,一段区间至少有一个 0。设表示前个数且满足与前个位置相交的限制的方案数。转移时枚举上一个的位置即可。可以前缀和优化。复杂度。
然而要注意的是,有关区间包含的去重问题一定要三思。千万记住:不要只比相邻的!不要 ban 掉前面的,应该是 ban 掉你当前的这个区间。注意枚举顺序。
Bombs
你有一个排列。你有一个 01 序列。对进行一次操作为:考虑:
- 把插入到集合中;
- 如果,就把集合中最大的数删除。
最后集合中剩下的数就是操作结果(如果有)。
现在给出排列和。设序列初始为,要求你对:
- 求出操作的结果并输出;
- 令(増加一个 bomb)。
。
随着 bomb 的增加,答案是不会增加的(不可能有数字复活)。
考虑排列中一个数,假设。那么在什么条件下答案?
所有大于等于的数都被删。也就说,中最靠右的的数的右边至少有一个 bomb,第二靠右的的数右边至少有 2 个 bomb,以此类推。
可以把的数的位置 +1,bomb 出现的位置 -1。那么条件就转化为,所有的后缀和都小于等于。
如果答案,那么我们就把减 1 并继续检查答案是否小于。
线段树维护后缀和即可。
时间复杂度。
Wise Men
给一个个点简单无向图。
对于长度为的排列,我们可以构造一个长度为的 01 串:。
现在对于所有个长度为的 01 串,求的排列的个数。
。
考虑容斥。容斥 01 串中的 0,用无限制减去强制为 1 的情况。也就是说,表示答案,则。我们考虑求。
可以理解为是,用若干条路径覆盖个点的方案数。其中每条路径的长度的给定的。比如表示用长度分别为的路径覆盖个点的方案数(换一种说法,就是,因为他们对应的路径长度集合都是)。
因此,其中表示路径长度集合。我们可以考虑求。的个数是拆分数,而,复杂度可以接受。
不妨先求出,表示用长度为的路径精确覆盖点集的方案数(哈密尔顿路径)。这个可以 DP 求出。那么可以理解为是,其中,且精确覆盖全集。由于的精确覆盖,因此本能地想到是不相交的或卷积。然而注意到我们只需要知道处的点值,因此普通的或卷积也是足够的(如果集合出现交集,则这种方案无法对的点值做贡献)。
因此就是的或卷积的处的点值。这样我们对于每个路径长度集合都可以计算出答案。
然后我们再枚举 01 串,求出它的路径集合即可。
最后容斥(FMT)回去。
时间复杂度。表示拆分出的部分的个数。能过。当然,也是可以优化的。优化就是在 DFS 枚举集合的时候顺便 FMT。
Sum of Prefix Sums
给你一棵带点权无根树。点权为。定义一条路径的权值为。求权值最大的路径的权值。
。
摘要:点分治,李超树。
考虑点分治。
容易想到把路径分成前后两部分:和。那么两部分的权值分别为和。前者可以用表示,后者可以用表示。因此整条路径的权值为。
对于每个结点我们都可以计算出它到分治中心的路径对应的和。因此我们要选择两个不同子树的和来更新答案。
考虑用数据结构维护的集合。然后用查询。那么这就是维护若干个一次函数,查询单点最大值的问题。可以使用李超树。可以标记永久化。
同时我们要求是不同子树。因此对于一个子树,先查再插入即可。然后再倒着做一遍处理反向的情况。
时间复杂度。
李超树的复杂度:在一个线段树区间上插入一条直线的复杂度是的。但是我们每次都是在根结点的区间上插入。因此总复杂度是的。
No Monotone Triples
对于一个序列,如果或者,那么称是单调序列。
若序列不含长度大于等于的单调子序列,则称是 no-triple 序列。
给出长度为的序列。次询问,询问区间的最长 no-triple 子序列。
。
手玩一下可以发现,no-triple 的长度最大为 4。
考虑对于每个(),求出最小的使得里有长度为 4 的 no-triple(长度为 3 的 no-triple 是类似的)。
那么条件可以转化为,求出最小的使得中存在使得,。
首先我们找到右边第一个比大的数。记为。
并且找到右边第一个比小的数。记为。
那么显然,。
另一方面,我们维护的两个非严格单调栈。设表示右边第一个大于等于的位置(即)。表示第一个小于等于。那么第一个栈中存储的就是,第二个栈中存的就是。
显然不能在任何一个栈中。不然就找不到比大的(或者找不到比小的)数了。
上面的这两个条件,是否是的充分条件?是的。
也就是说只要满足这两个条件,就一定能在中找到满足 no-triple 的条件。
因此我们只需要找到满足这两个条件的最小的即可。
构造方案:容易发现,一定存在方案使得分别在两个栈中。因此在栈上二分即可。
长度的 3 的 no-triple 是类似的。
然后我们离线,后缀即可。
时间复杂度。
Dreamoon Likes Strings
你有一个字符串。每次你可以删除的一个子串,满足中不存在相邻相同字符。删完后两边自动拼在一起。问最少多少次可以把删完。并输出方案。
。
考虑把中相邻相同字符都写下来。比如abbccddacdbbb
可以写出bcdbb
,记为。那么你删一个子串肯定是删一个极长的子串。于是可以发现,你的删除操作等价于:
- 在中删除开头或者末位一个字符;
- 在中删除两个相邻但不同的字符;
- 在中删除一个字符,且这个字符旁边存在与它相同的字符。
如果,那么我们就可以再删一次把删光。
那么我们肯定会先尽量使用 2 操作,多删几个字符。然后使用 1 操作。这就转化为一个经典问题:每次匹配两个不同类型的元素。问最多匹配多少个。设总数为,同类的最大数量为。则答案显然为。而现在的问题是我们还需要构造出方案。
- 如果,那么很容易构造方案。我们把其他的都往上“贴”就行。
- 如果。那么我们可以先随便搞。即遍历一遍,遇到相邻不同字符就双双删除。直到或者的时候就 break。这时就转化为了情况 1 了,于是再构造一下剩余的方案即可(当然在删除过程中,可能有别的类会变成)。
要注意细节的处理。
On the Bench
给你一个长度为的序列。问有多少个长度为的排列满足,不是完全平方数。
。
首先注意到,若和都是完全平方数,则也是完全平方数(传递性)。
因此问题转化为:有个带标号的球,每个球有一个颜色。你要把他们排成一排且相邻的球颜色不同。求方案数。
考虑容斥。同色不相邻 = 无限制 - 同色相邻。而同色相邻,可以理解为是把两个球捆在一起。
考虑 DP。设表示前种球,有个同色相邻的方案数。答案就是(假设一共种颜色)。
设第种球有个。那么我们可以枚举颜色的相邻的个数,假设是。那么这样的方案数是。然后考虑背包的合并,相当于把个球插板。
时间复杂度。
Kate and imperfection
设。
对于的子集,设。
对于(),求出的所有大小为的子集中,的最大值。
。
考虑的条件是什么?必要条件:中至多有一个数在中。如果要选一个数,显然我们会贪心地保留,删掉的倍数。
因此如果我们想删掉尽量少的数使得,则的倍数必须全部被删。
因此如果要求,则的倍数都要被删。不妨计算出表示要让,至少要删掉多少个数。即,要让,最多存在多少个数。
充分性:另一方面,如果存在和的倍数,那么至少是。
然后就简单遍历一遍统计答案即可。
时间复杂度。
Road to 1600
把依次填入的方格中。然后你需要访问每个格子恰好一次。有两种访问方式。
Rook 式:
- 从所在方格开始;
- 如果与它同行 / 同列中存在未被访问过的格子,选择一数字最小的格子走过去;
- 否则,从未访问过的方格中选择一个数字最小的方格并走过去。花费个代价。
Queen 式:
- 从所在方格开始;
- 如果与它同行 / 同列 / 同对角线(两个方向)中存在未被访问过的格子,选择一数字最小的格子走过去;
- 否则,从未访问过的方格中选择一个数字最小的方格并走过去。花费个代价。
现在要求你构造一种填数方案,使得 Rook 式的代价严格小于 Queen 式的代价。
。
考虑暴搜出小方格的情况。然后其他地方你构造成 Queen 和 Rook 走一样的路线。最后引导到这个小方格即可。
暴搜就随机一个的排列然后 check。
修订记录
- 2020年4月9日 创建文章