Present

给出长度为的序列,求

摘要:逐位计算。

考虑按位计算答案。考虑计算答案的二进制第位是否为计数)。由于高于的位不影响第位的数,不妨设。因此。那么我们要计算的就是

的奇偶性。

不妨将排序。枚举,在序列上二分查找即可。

时间复杂度

可以使用双指针 + 归并排序优化到

代码

Instant Noodles

给你一个个点的二分图,左部右部各个点。有条边。右部的点点权为

定义表示左部点集的邻居集合(显然都是右部的点)定义表示中的点的点权和。

摘要:哈希判邻居集合是否相等。

由于是和的 GCD,因此我们关系的是:对于两个右部点,他们是否同步出现(要么同时出现,要么同时不出现)。

如果两个点同步出现,那么我们就只用考虑它们的和。

推广之。若右部点集合中的点均同步出现,则我们只用考虑的点权和。

因此答案就是所有同步点集合的点权和的 GCD。

要判断右部点两个点是否同步出现,只需要判断它们的邻居集合是否相同即可。

若两个点的邻居集合不同,那么一定存在一个左部点集合使得这两个点没有同步出现。

使用哈希,时间复杂度

代码

Reality Show

给出长度为的序列,给出一个长度为的序列

你可以构造一个长度为的序列满足:

  1. (单增);
  2. (非严格单减)。

然后你需要对和一个集合做这样的操作:以的顺序考虑

  1. 你会获得的奖励;
  2. ,把加入并结束这次操作;否则把中删除,并令

你的得分是奖励之和减去

请构造满足条件的并最大化得分。输出得分。

摘要:倒序 DP。

首先注意到在第二步操作的时候,你以任意顺序操作,得分不变。

而我们操作的过程实际上可以看做是二进制的进位过程。

那么我们考虑倒着构造。那么我们每次构造的就是当前序列中最大的元素。

考虑 DP。设表示最大值为,且的人有个时的最大得分。

若我们在的开头插入(即新的),那么就可以对做一次背包:

另一方面,的时候可以进位到。但是不是所有都需要进位。因为我们只改变了,因此只需要对的部分进位即可。另一个事情是,会贡献到,则的范围每次除以 2。因此 DP 转移的复杂度是的。

总复杂度

代码

AND Segments

给出个限制。问有多少长度为的序列满足

按位考虑。限制转化为,一段区间全 1,一段区间至少有一个 0。设表示前个数且满足与前个位置相交的限制的方案数。转移时枚举上一个的位置即可。可以前缀和优化。复杂度

然而要注意的是,有关区间包含的去重问题一定要三思。千万记住:不要只比相邻的!不要 ban 掉前面的,应该是 ban 掉你当前的这个区间。注意枚举顺序。

代码

Bombs

你有一个排列。你有一个 01 序列。对进行一次操作为:考虑

  1. 插入到集合中;
  2. 如果,就把集合中最大的数删除。

最后集合中剩下的数就是操作结果(如果有)。

现在给出排列。设序列初始为,要求你对

  1. 求出操作的结果并输出;
  2. (増加一个 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,记为。那么你删一个子串肯定是删一个极长的子串。于是可以发现,你的删除操作等价于:

  1. 中删除开头或者末位一个字符;
  2. 中删除两个相邻但不同的字符;
  3. 中删除一个字符,且这个字符旁边存在与它相同的字符。

如果,那么我们就可以再删一次把删光。

那么我们肯定会先尽量使用 2 操作,多删几个字符。然后使用 1 操作。这就转化为一个经典问题:每次匹配两个不同类型的元素。问最多匹配多少个。设总数为,同类的最大数量为。则答案显然为。而现在的问题是我们还需要构造出方案。

  1. 如果,那么很容易构造方案。我们把其他的都往上“贴”就行。
  2. 如果。那么我们可以先随便搞。即遍历一遍,遇到相邻不同字符就双双删除。直到或者的时候就 break。这时就转化为了情况 1 了,于是再构造一下剩余的方案即可(当然在删除过程中,可能有别的类会变成)。

要注意细节的处理。

代码

On the Bench

给你一个长度为的序列。问有多少个长度为的排列满足不是完全平方数。

首先注意到,若都是完全平方数,则也是完全平方数(传递性)。

因此问题转化为:有个带标号的球,每个球有一个颜色。你要把他们排成一排且相邻的球颜色不同。求方案数。

考虑容斥。同色不相邻 = 无限制 - 同色相邻。而同色相邻,可以理解为是把两个球捆在一起。

考虑 DP。设表示前种球,有个同色相邻的方案数。答案就是(假设一共种颜色)。

设第种球有个。那么我们可以枚举颜色的相邻的个数,假设是。那么这样的方案数是。然后考虑背包的合并,相当于把个球插板。

时间复杂度

代码

Kate and imperfection

对于的子集,设

对于),求出的所有大小为的子集中,的最大值。

考虑的条件是什么?必要条件:中至多有一个数在中。如果要选一个数,显然我们会贪心地保留,删掉的倍数。

因此如果我们想删掉尽量少的数使得,则的倍数必须全部被删。

因此如果要求,则的倍数都要被删。不妨计算出表示要让,至少要删掉多少个数。即,要让,最多存在多少个数。

充分性:另一方面,如果存在的倍数,那么至少是

然后就简单遍历一遍统计答案即可。

时间复杂度

代码

Road to 1600

依次填入的方格中。然后你需要访问每个格子恰好一次。有两种访问方式。

Rook 式:

  1. 所在方格开始;
  2. 如果与它同行 / 同列中存在未被访问过的格子,选择一数字最小的格子走过去;
  3. 否则,从未访问过的方格中选择一个数字最小的方格并走过去。花费个代价。

Queen 式:

  1. 所在方格开始;
  2. 如果与它同行 / 同列 / 同对角线(两个方向)中存在未被访问过的格子,选择一数字最小的格子走过去;
  3. 否则,从未访问过的方格中选择一个数字最小的方格并走过去。花费个代价。

现在要求你构造一种填数方案,使得 Rook 式的代价严格小于 Queen 式的代价。

考虑暴搜出小方格的情况。然后其他地方你构造成 Queen 和 Rook 走一样的路线。最后引导到这个小方格即可。

暴搜就随机一个的排列然后 check。

暴搜代码

代码