CF 练习题

Cow Program

由于两种操作只在 \(x\) 的加减上有区别, 故而我们可以用 \(typ\) 直接区分操作。

\(typ = 0\) 表示操作 \(1\)
我们考虑记忆化搜索, 令 dp[typ][i] 表示 当 \(x = i\), 执行到 \(typ\) 操作时 \(y\) 的变化量。
由于我们只关心操作的编号 和 \(x\) 的值, 而 \(y\) 的变化量也只和这些有关, 所以才能做到记忆化。

Zero Tree

题意简化为: 每次我们可以将 任意一个包含节点 \(1\) 的联通块中的所有节点的权值 加 \(1\) 或 减 \(1\), 求最少的操作次数使得所有节点的权值为 \(0\)

对于每个节点来讲, 深度越大的节点能修改它的方案越少, 故而贪心的从下向上依次修改节点权值为 \(0\)

注意到对于一个子树来讲, 要修改它的子节点就必须修改它的根节点, 故而考虑树形 DP 求解。

由于我们可以任意选择联通块, 那么我们只需在意子树中需要修改幅度最大的值, 因为我们可以随意改动修改的形态使得满足在我们需要的地方加减。

需要将加减分开统计。

Maxim and Restaurant

我们令 dp[i][j][k] 表示前 \(i\) 个人中选择 \(j\) 个人, 占据 \(k\) 个空间的方案数, 可以省略第一维 \(i\)

状态转移方程为 dp[j][k] += dp[j - 1][k - a[i]], 即背包问题选择第 \(i\) 个人。
对于一种方案 dp[j][k] 来讲, 它的可能情况共有 \(dp[j][k] \times j! \times (n - j)!\), 表现为将已经选择的人和未选择的人随机排列的总方案数。

那么对于我们要求的期望人数来讲, 由于每个人的贡献都只有 \(1\), 那么我们相当于求解每个人出现的概率之和。 即 答案为 $\dfrac{\sum\limits_{j = 1}^{n}\sum\limits_{k = 0}^{m}dp[j][k] \times j! \times (n - j)!}{n !} $

Sereja and Periods

我们可以先对两个字符串进行匹配, 用 \(fail\) 数组记录从字符串 \(t\) 的位置 \(i\) 开始, 最多能在 经历一整个 \(s\) 后匹配到的位置, 注意这里的匹配不需要严格相邻, 是和 \(s\) 中的序列的匹配。

当我们匹配到 \(t\) 的终点时, 我们认为从当前位置可以完成一次匹配, 我们有 \(cnt\) 记录最多能匹配的次数。

那么此时, 对于 \(s\) 串的重复次数, 我们实际上是不停地跳 \(fail\) 指针, 统计经过 \(b\) 次循环后, 能匹配多少次 \(t\)

由于我们要求解的是 \(d\) 次循环的 \(t\), 故而答案 \(\div d\) 即可。
时间复杂度为 \(O(mn + b)\)

Apple Tree

注意, 文中的子树指的是 儿子节点所代表的子树。

题意 : 一个根为 1 的树,叶子节点有点权,一个点是平衡的当且仅当它 儿子节点所代表的子树 都有相同的权值和。 只能减少点权,求至少减掉多少可使得树平衡。

那么相当于我们可以求出每个节点的相对权值大小。
若这个节点子节点个数为 \(x\) ,那么每个子树的就占这所有子树和的 \(\frac{1}{x}\)

这么 dfs 下去就可以得到每个叶子节点应该占的比重。
由于 分子都是 \(1\), 所以我们只存分母。

那么具体到每个节点最少得有多少,就得求一下这些分母的 \(\text{lcm}\),这样就能搞定每个叶子最小得多大。

因为只能减不能加,我们得求一下这最后答案可能的上界是什么,即叶子对应权重除以所占比例,最后取最小值就是上界。

然后得搞定可达到的上界,显然,若树是平衡的,那么它的叶节点值的和就得是他们所占比例的和的倍数 。

就是说如果叶子所占比重分别为 \(2:2:1:1\),那么叶子值的和就得是 \(k(2+2+1+1)\)

因为我们上面求出来的比例可能不是最简整数比,所以要把 \(\gcd\) 除掉最后取离上界最近的是比例的和的倍数作为结果

Lucky Common Subsequence

求 两个串的最长公共子序列比较模版, 考虑不包含 virus 子串的问题。
考虑设 dp[i][j][k] 表示第 \(1\) 个串 匹配到 \(i\), 第 \(2\) 个串匹配到 \(j\), virus 匹配到 \(k\) 时的最长子序列。

对于 \(i, j\) 来讲, 直接转移到 \(i + 1, j + 1\) 即可。

但对于 \(k\) 来讲, 由于它要求的是 子串, 我们需要转移到 失配指针处, 以解决类似于 \(\texttt{abcabd}\) 匹配 \(\texttt{abcabc}\)\(\texttt{d}\) 处失配的问题。

Book of Evil

我们考虑转化题意, 将 求有多少个节点距离 怪兽 小于 D 转化为 求有多少节点距离 离他最远的怪兽小于 D。

那么此时, 我们只需要维护每个节点到 所有怪兽的最大距离即可。
考虑 树形 DP
dp[i][1] 表示 \(i\) 到其子树内有怪物的点的最大距离
dp[i][2] 表示 \(i\) 到其子树内有怪物的点的次大距离
dis[i] 表示 \(i\) 到其子树以外的节点的最大距离

那么这时, 我们可以通过两次 dfs 直接求解出 \(dp\) 数组 和 \(dis\) 数组。
最后判断即可。

Maximum Submatrix 2

贪心 ??

既然只能改变行的次序, 我们考虑枚举每一列, 以该列为子矩阵的一边。
那么此时, 我们只需要考虑从该列向一个方向拓展, 每一行最多可以拓展几次。

即: 在 有 \(n\) 个数的集合中选取 \(x\) 个数, 总价值为 \(x \times min\{\text{所选的数}\}\)

考虑贪心的选取, 枚举 所选的数的个数 x, 那么此时我们只需要求第 x 小的数即可。

时间复杂度为 \(O(n^2 \log n)\)

MEX Sequences

我们令 \(f(i, j, 0/1)\) 表示从 第 \(1\) 位 到 第 \(i\)\(\text{mex}\) 等于 \(j\) 的方案数, \(0\) 表示没有比 \(\text{mex}\)\(1\) 的数, \(1\) 表示有比 \(\text{mex}\)\(1\) 的数。

当出现了在第 \(i\) 位的一个数 \(j\),推出可能的可以构成的方案是 \(f(i-1, j,0),f(i-1,j+1,0),f(i-1,j+1,1),f(i-1,j-1,0),f(i-1,j-1,1)\)

分别表示 \(\text{mex}\) 等于 \(j\) 且不存在数 \(\text{mex} + 1\)\(j + 1\)\(\text{mex}\) 等于 \(j + 1\) 的有或者没有 \(\text{mex} + 1\)\(j + 2\) 两种,\(\text{mex}\) 等于 \(j−1\) 的有或者没有 \(\text{mex} + 1\)\(j\) 两种。
注意如果选择 \(\text{mex}\) 等于 \(j\) 且此时存在 \(\text{mex} + 1\),就会将当前 \(\text{mex}\) 直接增大到 \(\text{mex} + 2\),不满足要求,故不能取。

然后考虑对于 \(f\) 数组的转移,考虑选择了 \(j\) 之后有哪些状态可能存在新的方案,

首先所有的 \(f(i,j,0/1)\) 都有对应的 \(f(i - 1,j,0/1)\) 种方案,也就是直接不取。
\(f(i,j + 1,0)\) 可以由 \(f(i-1,j-1,0)\)\(f(i-1,j+1,0)\)(选择了之后 \(\text{mex}\) 不变,但是确实是一种新的方案)转移。
\(f(i,j+1,1)\) 可能方案数是原来的两倍。
\(f(i,j-1,1)\) 可以由 f(i−1,j−1,1)转移,
\(f(i,j-1,1)\) 此时由于存在了 \(\text{mex} + 1\),可以由 \(f(i,j-1,0)\)\(f(i,j-1,1)\) 转移过来。

可以直接把第一维压掉, 时间复杂度 \(O(n)\)

初状态 \(f(0, 0) = 1\), 答案即为 \(\sum\limits_{i = 1}^{n}f(i, 0) + f(i, 1)\)

Bath Queue

我们令 \(f(i, j, k)\) 表示前 \(i\) 个房间去了 \(j\) 个人, 最长队列长度为 \(k\) 的方案数。

状态转移方程为 :

\[f(i, j + x, \max(\lceil \frac{x}{a_i} \rceil, k)) = \sum f(i - 1, j, k) \times \binom{n - j}{x} \]

其中 x 表示当前房间进入的人数。 由于每个人不同, 所以我们要在剩下的 \(n - j\) 个人中选择 \(x\) 个, 故方案数要乘上 \(C_{n - j}^{x}\)

那么总方案数 \(T = \sum_{i = 0}^{n} f(m, n, i)\)

由于我们所求期望为 最长的队伍的长度, 故而答案即为

\[\frac{1}{T}\sum\limits_{i = 1}^{n} i \times f(m, n, i) \]

Oranges and Apples

我们按照苹果的个数为关键字倒序排序得到新的序列

\[a_1, a_2, a_3, \dots , a_n \]

因为 \(n\) 是奇数,我们把最大的 \(a_1\) 先拿到一边。如此,对于苹果,我们有两种选的方案 :

  • 选所有下标为奇数的 \(a_i\)
  • \(a_1\) 与 下标为偶数的 \(a_i\)

不难发现,这两种方案均满足苹果大于其总数的一半,所以我们再来考虑无序的橘子。又因为如果方案一的橘子数不满足题意,则方案二必定满足,所以我们只需要比较两种方案哪一种橘子数量多就好了

Balance

我们发现, 一个位置的字符可以被替换成其他字符, 当且仅当它前方 或者 后方存在一个 其他字符。

我们考虑从 \(1\)\(n\) 递推, 那么此时, 我们只需要考虑其前方所有的字符即可(由于其后方的字符已经确定, 而每次修改当前位置的字符会改变后方的字符)。

我们令 \(f(i, a, b, c)\) 表示 在位置 \(i\), 已经有了 \(a\)\(\texttt{a}\)\(b\)\(\texttt{b}\)\(c\)\(\texttt{c}\) 的方案数。

\(nxt(i, 0/1/2)\) 分别表示位置 \(i\) 处的下一个 \(\texttt{a}\) / \(\texttt{b}\) / \(\texttt{c}\) 所在的位置。

那么我们的转移方程即为 :

\[\begin{cases} f(nxt(i, 0), a + 1, b, c) += f(i, a, b, c)\\ f(nxt(i, 1), a, b + 1, c) += f(i, a, b, c) \\ f(nxt(i, 2), a, b, c + 1) += f(i, a, b, c) \end{cases}\]

关于这个方程的一些问题与解答 :

  • 为何直接转移到 \(nxt\) 而不是 \(i + 1\) ?

  • 我们修改字符是并不是直接修改, 而是将当前位置 到 \(nxt\) 全部覆盖为 \(nxt\) 位置的字符。 如果转移到 \(i + 1\) 的位置并且 \(nxt\) 不变的话, 那么它还可以再次计算覆盖 \(i + 1\)\(nxt\) 的位置的方案数, 如果第 \(i\) 位置的字符 与 \(nxt\) 相同, 那么这两次所得到的字符串完全相同。 这样的话就会重复计算答案。

  • 既然是 覆盖 \(i\)\(nxt\) 的位置, 为何 计算字母个数时只 加 \(1\) ?

  • 这就考虑到我们只遍历到了 位置 \(i\), 而当我们遍历到 \(i + 1\) 的位置时, 这个位置的字符可能被再次修改, 故而不用考虑。

我们最终所求答案即为 :

\[\sum f(i, a, b, c) \times [a + b + c = n ][\text{abs}(a - b) \le 1][\text{abs}(b - c) \le 1][\text{abs}(a - c) \le 1] \]

时间复杂度为 \(O(n)\)

Jeremy Bearimy

对于最小值,即每条边的使用次数最小,那么对于以 \(u\) 为根节点的一棵树,设
\(v\) 是与它相连的子树的根,那么可以得到: 当子树的 \(\text{size}\) 为偶数时,我们完全可以让子树自己内部消化,而当子树的 \(\text{size}\) 为奇数时,则边 \((u,v)\), 一定会被经过。

对于最大值,我们不能单纯的取反后再按最小值的方法做,我们可以对于每一条边为单位,让这一条边尽可能多的被通过,那么,对于边
\((u,v)\), 我们的最多经过次数即为 \(\min(siz[v], n - siz[v])\),换而言之,这条边连接的两个子树的 \(\text{size}\) 最小值。 既然知道最多贡献次数了之后,那么其对于答案的贡献就为 \(\min(siz[v], n - siz[v]) \times e[i].val\)

Bits

由于题目求 \(1\) 的个数最多 且 最小 的那个数,不难想到这样的贪心策略:

从最低位开始(二进制),每次尝试将 \(l\) 的当前位变为 \(1\)。如果变为 \(1\) 后会大于右边界 \(r\),则终止循环,输出当前的 \(l\)

The Awesomest Vertex

观察这个式子, 我们首先考虑求 从根节点 到 叶子节点的前缀和, 记为 \(qz_a(u)\)\(qz_b(u)\), 那么此时, 我们所求即为 \(f(u) = |qz_a(u)| \times |qz_b(u)|\)

那么此时, 两个操作分别等价于 :

  • 给定 \(v, x\), 将以 \(v\) 为根的子树中的所有节点的 \(qz_a\) 加上 \(x\)

  • 给定 \(v\), 求解 子树中 \(f(x)\) 的最大值。

由于 \(qz_b\) 是定值, 我们考虑 \(qz_a\) 变化造成的影响。

对于一个变化量 \(\Delta x\), 变化后的 \(f(x) = |qz_b| \times \Delta x + |qz_a| \times |qz_b|\)

由于 绝对值 有一个性质:\(|x| = \max(x, -x)\), 且我们恰好要求最大值,

那么此时, 我们等价于维护 \(qz_b \times \Delta x + qz_a \times qz_b\)\(-qz_b \times \Delta x - qz_a \times qz_b\) 的较大值。

由于我们的操作与 子树 有关, 考虑通过 dfs 序 + 线段树 维护每个子树。

具体来讲, 线段树每个节点维护这几个值 \(k,b,lim,tag\)\(k\) 就是斜率,\(b\) 就是常量,\(lim\) 表示在增加多少是最大值会改变,\(tag\) 是加法标记

修改就判一下当前节点的 \(lim\) 是不是比增加量小,如果大一些,直接修改整个区间,如果小,那就递归它的子节点修改。

Multihedgehog

Connected Components?

直接用 map 记录不存在的边, 用 bfs 染色时间复杂度为 \(O(n^2\log m)\)

考虑一种优化方式, 我们用数据结构记录还没有被遍历到的点, 每次 bfs 仅遍历这个数据结构中的点。 我们考虑时间复杂度, 由于初状态结构中有 \(n\) 个点, 末状态没有点, 每个点被遍历第一次时要么会被删除, 要么由于没有边而保留。 这样的话, 将数据结构中的点全部删除期望复杂度为 \(O(n + m)\)。 由于本题中的 \(m\)\(n\) 同阶, 故而该复杂度可行。

再考虑另一种方法, 我们直接将度与数最大的点相连的点全部标记, 然后对于其他点用 并查集 暴力维护。 这样, 对于第 \(1\) 步而言, 我们期望直接找到 \(n - \frac{m}{n}\) 个点组成联通块, 由于 \(m\)\(n\) 同阶, 故而这样的复杂度可行。

Trash Problem

具体的,对于上述插入节点的操作,我们有如下代码 :

set < int > s;  // 维护节点的位置
multiset < int > slen; // 维护间距
void add(int x)
{
    set < int > :: iterator it = s.lower_bound(x); // 找到大于等于 x 的节点。 
    int R = -1, L = -1; // 记录右节点, 左节点的位置
    if(it != s.end()) { // 如果存在右节点
    	R = *it; 
    	slen.insert(R - x); 
	}
	if(it != s.begin()) { // 如果存在左节点
		L = *(-- it);
		slen.insert(x - L);
	}
	if(L != -1 && R != -1) { // 如果左右节点都存在的话
		slen.erase(slen.lower_bound(R - L));
	}
	s.insert(x); // 最后插入 x 节点。 
    return;
}

最大XOR和路径 & Shortest Path Problem?

题目大意:在一个图中求最大 xor 和路径。

思路解析:这道题的关键在于如果重复经过一条边偶数次那么这条边对于答案的贡献为 \(0\)。这样的话就可以在到达任意一个结点 \(x\) 之后随意绕一个环一圈然后再走回 \(x\),这样新增长的贡献就是这个环的异或和。

再整理一下思路,首先枚举一条 \(1\)\(n\) 的路径,然后再算这条路径与所有环中任选任意多个能达到的最大异或和。而求任意多个的最大异或和自然要用线性基。所以每枚举到提个环就尝试让它入线性基,最后再求最长 xor 路径即可。注意,那个 \(1\)\(n\) 的路径可以是任意一条,因为这条路径异或和 xor 这条路径所在的环的异或和等于这个环的另一半的异或和。即若 \(a \oplus b=x\)\(a \oplus x=b\)

Edgy Trees

正难则反, 考虑求不经过一条黑色边的路径数。 由于原图是一棵树, 那么树上任意一条边都是割边, 即从一个联通块通向另一个联通块必须要经过他们之间的边。

那么我们考虑不加入黑色边, 此时得到了几个联通块, 每个联通块中不包含黑色边。 我们所求的路径即为仅在这些联通块内部选 \(k\) 点, 方案数为 \(\sum \binom{\text{联通块点的个数}}{k}\)

总方案数为 \(\binom{n}{k} - \sum \binom{\text{联通块点的个数}}{k}\)

Nezzar and Symmetric Array

具体来讲, 我们可以得到 \(d_i\) 关于 \(a\) 的表达式:

\[d_{i \times 2} = d_{i \times 2 - 1} = i \times (a_{2 \times i} - a_{2 \times i - 1}) + \sum\limits_{k = i + 1}^{n}a_{2 \times k} - a_{2 \times k - 1} \]

由于在 \(i = n\) 时可以直接得到 \(a_{2 \times i} - a_{2 \times i - 1}\) 的值, 故而我们可以直接递推求解。

Moodular Arithmetic

我们知道:

\[f(k \times x \bmod p) \equiv f(k^2 \times x \bmod p) \equiv f(k^3 \times x \bmod p) \equiv \dots (\bmod p) \]

这个循环直到 出现循环节时才会停止, 相当于形成了一个环路。那么我们要做的实际上是将 \(1 \sim p\) 按照循环节 分组, 每一组互不干扰, 我们只需要在每一组中任选一个数即可。 注意特判 \(k = 0\) 的情况。

Lipshitz Sequence

我们先要证明一个结论:
对于一个区间的 \(Lipschitz\) 常数 \(k\),应满足:

\[k = \max\limits_{i = l}^{r - 1}\dfrac{a_{i + 1} - a_i}{i + 1 - i} \]

\[k = \max\limits_{i = l}^{r - 1}a_{i + 1} - a_i \]

口胡一下, 对于一个三元组 \(a_1, a_2, a_3\) , 我们有 \(3\) 种选择方案, 假设当前选择 \(\{a_1, a_2\}\), 当我们重新选择 \(\{a_1, a_3\}\) 时, 即满足 \(\dfrac{a_2 - a_1}{2} \le \dfrac{a_3 - a_1}{3}\), 即 \(a_3 \le \dfrac{3a_2 - a_1}{2}\)。 我们再与 \(\{a_2, a_3\}\) 比较, \(\dfrac{a_3 - a_2}{2} \textcircled{} \dfrac{a_3 - a_1}{3}\), 即 \(a_3 \textcircled{} 3a_2 - 2a_1\), 显然, 我们可以得出 \(\{a_2, a_3\}\) 更优。

注意到 \(q \le 100\), 我们只需要支持 \(O(nq)\) 即可。

观察到相邻区间的 \(k\) 值可能出现多次, 我们考虑用单调栈处理处每个 \(k\) 值出现的范为, 最终答案即为 每种 \(k\) 值出现范围 \(\times\) 该范围内的区间个数。

Tavas and Malekas

一个简单的想法是求出所有不被文本串覆盖的位置, 那么我们的答案即为 \(26^{\text{没有被覆盖的位置的个数}}\)

那么现在问题就是判断是否合法。 我们考虑用字符串 HASH 解题, 维护字符串的前缀和后缀, 倘若两个位置的的文本串有重叠的部分, 我们就需要判断这重叠部分是否完全相等。

You Are Given a WASD-string

容易发现,左右和上下互不影响,可以分开处理,这里以左右举例。

定义向左走一格 \(−1\),向右走一格 \(+1\),求个前缀和找到最小值和最大值,和出现最值的最早时间与最晚时间。定义为 \(l_1, r_1, l_2, r_2\)

只有当我们放了一个 A 或 D 使得所有最大值 \(−1\) 且最小值不变,或最小值 \(+1\) 且最大值不变时,面积才会减小。

假如我们要让最大值 \(−1\),那么当且仅当 \(r_1 < l_2\) 且在坐标 \((r_1,l_2)\) 中存在一个数不等于 \(r_1\) 对应的值。

String

注意到 \(k \le 10^5\), 远小于 \(n^2 \le 10^{10}\)

我们考虑直接枚举 \(k\), 利用 priority_queue 来维护字典序最小的子串, 剔除掉前 \(k\) 小的子串。 我们不可能直接将所有子串一次性加入堆中, 考虑一种贪心的想法, 由于字符串是按照字典序进行比较,
那么首字母小的字典序一定小。 我们最初只将每个位置的字符加入堆中, 当认定当前子串字典序最小后, 将其弹出队列, 并加入 当前子串向后拓展一位的字符串, 这样所得到的满足当前堆中一定有除去弹出子串外字典序最小的字符串, 保证了堆中的元素个数始终都为 \(O(n)\), 那么堆的时间复杂度为 \(\log n\)

最终时间复杂度为 \(O(k \log n)\)

Grime Zoo

贪心的想法: 最优解的填数方案是存在于字符串中某一个 ? 前边的 ? 全部填 \(0\) 或者 \(1\),后边的填 \(1\) 或者 \(0\), 最大化 \(\texttt{01}\)\(\texttt{10}\) 序列的个数。

然后考虑对每对 \(0\)\(1\)的贡献计算,对原数组从头到尾扫一遍,扫到 \(0\) 对价值贡献即为 \(pre_1 \times y\),反之扫到 \(1\)则为 \(pre_0​ \times x\)。其中 \(pre_{0/1}\)​ 表示当前位之前有多少个 \(0\)\(1\)

与之类似, 再从后往前扫一遍, 得到全填 \(0/1\) 所得贡献的后缀, 记为 \(suf_{0/1}\)

考虑上述贪心, 我们枚举分界点, 求出所有可能贡献中的最小值即可。

Vasily the Bear and Sequence

我们考虑从大到小枚举 \(k\), 那么此时, 我们选择的数的二进制表示的第 \(k\) 位 一定要为 \(1\)

考虑数的选择, 对于 & 的操作来讲, 我们想要二进制 \(1 \sim k - 1\) 位为 \(0\), 那么选择越多的数越好。 故而我们实际上只用判断 所有二进制表示第 \(k\) 位为 \(1\) 的数的 & 和是否满足题意即可。

Video Cards

我们实际上求的是 \(\max_{k = 1}^{n}\{\sum_{i = 1}^{n}\lfloor\dfrac{a_i}{a_k}\rfloor \times a_k\} = \max_{k = 1}^{n}\{a_k \times \sum_{i = 1}^{n}\lfloor\dfrac{a_i}{a_k}\rfloor \}\), 故而我们只需要求 \(\sum_{i = 1}^{n}\lfloor\dfrac{a_i}{a_k}\rfloor\) 即可。

考虑到 \(b \times a_k \sim (b + 1) \times a_k - 1\) 对答案的贡献相同, 都为 \(b\), 这就启发我们统计各个数字出现的次数。 由于 \(a_i \le 2 \times 10^5\) , 故而可行。

Masha-forgetful

给定 \(n\) 个字符串 和 一个文本串, 长度都为 \(m\), 求一种 将 文本串分割为 \(k\) 段, 每一段都是 \(n\) 个字符串之一的子串 的方案。

首先有一个结论: 对于任意长度大于 \(1\) 的子串, 它都可以用长度为 \(2\)\(3\) 的子串表示出来。(类似于 小凯的疑惑)

由于只需要构造一组合法的方案, 我们只需要将所有长度为 \(2\)\(3\) 的子串扣出来, 然后与文本串进行匹配。

可以考虑用类似于 DP 的方式, 记录前驱方案, 然后输出即可。

Labyrinth

在有向图上找两条起点和终点相同的路径满足除了起点和终点外没有重复经过的点。

我们考虑 bfs, 从起点的下一个节点开始向外拓展, 并将一个节点的编号作为 颜色 标记由该节点拓展出的路径。 如果存在一个节点同时被两种颜色标记, 我们就说找到了一个合法终点。

因为是两条没有重复点的不同路径,因此除了终点之外路径上的任何一个点都只有一个父节点, 故当我们找到终点时就可以利用跳 \(fa\) 数组来获得路径信息 。

Cow and Snacks

\(n\) 种花,\(k\) 个客人,每个人喜欢两种编号不同的花。但是每种花在花店里只有一束。
客人按顺序进入花店,会买走所有她喜欢且仍在店铺里的花。如果一个客人买不到任何一束花,那么她就会十分沮丧导致变成肥宅。现在你可以自己安排这 \(k\) 个人的顺序,使得肥宅的数量最小。

考虑将一个人喜欢的两种花\((x, y)\)连边, 那么对于这样所形成的图来讲, 我们发现, 对于任意一个联通块(链和环)来讲, 假如点的个数为 \(c\), 那么我们最多可以满足 \(c - 1\) 个人对花的需求。

那么这时问题就变成统计联通块的个数, 可以用并查集解题。

假如联通块的个数为 \(C\), 那么最多能被满足的人的个数为 \(n - C\), 不能被满足的人数即为 \(m - (n - C)\)

Wormhouse

给定一个图和一条图中的欧拉回路,求另一条欧拉回路,使得它的字典序比给的回路大。

由于 \(n \le 100\), 我们考虑直接暴搜解题。

用一个bool记录当前是否和原回路字典序相等,如果相等就不用考虑比原字典序小的点能否到达。因为要找欧拉回路,所以走完一条边之后就可以直接断开这条边,回溯时在连回来。

如果已经走过了 \(m\) 条边,需要判断一下这条路径是否为欧拉回路,以及字典需是否严格大于原序列。

Graph Cutting

给你一个 \(n\) 个点 \(m\) 条边的简单无向图,问你能否将这个图分割成 \(2m\)​ 个长度恰好为 \(2\) 的路径,使得每条边都恰好出现一次。

我们先考虑原图是一棵树的情况, 对于一个子树 \(u\) 来讲, 我们首先将叶子节点两两配对得到 \(\text{V}\) 形的链。 如果叶子节点的个数为奇数个, 我们将多余的一个节点保留下来, 记为 \(v\)。 当我们遍历 \(fa(u)\) 这棵子树时, 优先将 \(fa(u) - u - v\) 这条链输出。

那么对于图来将, 实际上是在 dfs 树上增加了一些返祖边。 考虑这些边的处理, 对于一条返祖边 \(u \rightarrow v\), 我们可以将这条边视作子树 \(v\) 连向子节点的一条边, 将其加入 \(vec_v\) 中, 等到回溯到 \(v\) 时与其他树边一同处理。

Lovely Matrix

给定一个 \(n \times m\)的矩阵, 要求重新排列这 \(m\) 列,使得每行都非严格单调递增。输出可能的排列。矩阵中元素值为 \(-1\) 的位置可以替换成任何数。

我们将每一列看做一个节点, 那么根据每一行的元素都要非严格单调递增我们可以得出列与列之间的先后顺序。 考虑用拓扑排序来得到列的排列。

注意到对于相同的元素而言, 他们都会连很多相同的约束边, 比如一列中都是两种元素, 这样的话会连 \((\frac{m}{2})^2\) 条边。 考虑新建一些节点来简化表示这些关系即可。

Love Triangles

给定 \(n\) 个点 和 \(m\) 条边, 每条边的权值为 \(0\)\(1\), 要求增加一些权值为 \(0\)\(1\) 的边使得图成为一个完全图并且对于任意三个节点他们之间的三条边的异或和为 \(1\)

考虑不同权值的边产生的约束:
一个权值为 \(1\) 的边 \((u, v)\), 对于任意一个其他节点 \(x\), 边 \((u, x)\) 和 边 \((v, x)\) 的权值应该相同。
一个权值为 \(0\)的边 \((u, v)\), 对于任意一个其他节点 \(x\), 边 \((u, x)\) 和 边 \((v, x)\) 的权值应该不同。

这就启示我们最终的图一定是几个集合, 集合内部的边边权权为 \(1\), 连接集合的边的边权为 \(0\)

我们看一个简化版的问题:图的要求与原题相同,点数为 \(n\),不给出已知边。那么答案显然为 \(2_{n - 1}\)。先固定第一个点,其余的 \(n - 1\) 个点均有两种选择,加入 \(1\) 号点或与 \(1\) 号点对立。

我们考虑将已经确定好大小关系的联通块缩成一个点, 转化为上述问题, 假定最终得到的独立集有 \(k\) 个, 我们的答案即为 \(2_{k - 1}\)

Computer Game

由于 Boss 的血量 \(\le 1000\), 那么我们可以在 \(2000\) 以内的时间完成游戏(如果可能的话), 可以直接枚举时间。

我们假设 Boss 的血量恢复为 \(delta\), 那么每个卷轴的作用即将 \(delta\) 减去一个值。 注意到 \(delta\) 的值是不断减小的, 也就是说, Boss 的血量要么为 \(100\%\), 要么小于上一个时刻的血量, 即 Boss 的血量单调递减。

由于可以使用卷轴的约束是要求血量小于一个值, 所以当某个时刻 Boss 的血量降低到给定值后, 在这个时刻之后我们一直可以选择使用该卷轴。故而我们只需要在每一个时刻贪心的选择伤害值最大的卷轴即可。

对于无解的判断即为 当前无可用卷轴、当前 \(delta > 0\) 和 当前血量大于等于上一次的血量。

Population Size

给定只包含 正整数\(−1\) 的一个长度为 \(n(n \le 2×10^5)\) 的序列 \(a(a_i​ \le 10^9)\)\(−1\) 可以被替换成任意正整数。求该序列最少可以划分成几个等差数列。
需要注意,公差为 00 也是等差数列

由于我们想让等差数列的个数尽可能的少, 故而我们将每个元素尽可能的向上一个等差数列合并, 实在无法合并时再新建一个等差数列。

我们考虑枚举数列前尚未被遍历的两个不是 \(-1\) 的数 \(a_x\)\(a_y\)
此时有如下情况:

  • 有一个数不存在, 那么此时我们可以直接将 \(-1\) 变成其中一个数, 这样组成的数列一定合法, 答案加 \(1\)
  • \((a_y - a_x) \bmod (y - x) \not = 0\), 那么此时区间 \([x, y]\) 之间的数无法组成一个等差数列, 考虑将 区间 \([x, y)\) 视作一个等差数列, 继续递归处理 \([y, n]\)
  • 由于 \(-1\) 只能变成正整数, 我们需要考虑在组成等差数列时 \(-1\) 是否会被视作一个非正整数, 即判断 \(a_i = a_x - (y - i) \times delta \le 0\) 是否成立, 如果成立的话, 即将 区间 \([x, y)\) 视作一个等差数列, 继续递归处理 \([y, n]\)

如果上述条件都满足的话, 我们继续向后遍历, 如果当前数不为 \(-1\) 且 不满足等差数列 或者 当前数为 \(-1\) 但需要替换成一个非正整数的话,就停止遍历。

重复进行上述过程直到将数列全部遍历一遍, 时间复杂度为 \(O(n)\)

Chessboard Billiard

如果两个小球可以到达,那么它们就可以到达同一个边界。故两个小球可达的边界位置不同等价于这两个小球不可达。

我们可以用并查集维护所有边界位置的关系,最终得到的不同连通分量的个数即为最多可以放置的小球数。

Suspects

注意到每个人的话只有是 和 非 两种, 当我们确定犯人后, 每人的话都可以被判断真假, 由于犯人只有一个, 考虑 \(O(n)\) 枚举犯人,

如果 \(i\) 指控一个人是罪犯:经过如上处理,发现他不可能是罪犯,则为假话;如果他可能是罪犯且嫌疑人数为 \(1\),则为真话;否则不确定。

Cipher

如果把每个字母看成一个数, 那么我们所做的操作即为 对两个相邻数分别进行 \(+1\)\(-1\)。 这样的话, 每个字母加起来的和保持不变。

我们可以将改问题抽象:给定一个数 \(s\),把他分成 \(n\)\([1,26]\) 之间的数字的和有多少种分法。

我们考虑 DP 解题, 令 \(f(i, j)\) 表示前 \(i\) 个数的和为 \(j\) 的方案数, 那么:

\[f(i, j) = \sum\limits_{k = 1}^{26}f(i - 1, j - k) \]

这样的时间复杂度为 \(O(26^2 n^2)\)。 由于该递推关系与字符串的具体形态无关, 与 字符串长度 和 字符之和有关, 故而我们可以 \(O(1)\) 回答询问。

Quantity of Strings

对于一个回文串 \(s\) 来讲, 我们有 \(s_i = s_{n - i + 1}, i \in [1, n]\), 由于我们要求对于原串的任意一个长度为 \(k\) 的子串都必须为 回文串, 那么我们可以得到一些位置的字符必须相等的约束条件。 当满足这些条件是, 原串就符合题意。 由于每个位置可以填 \(26\) 中字符, 故而我们考虑统计独立集的个数, 那么最后的答案即为 \(26^{\text{独立集的个数}}\)

posted @ 2023-09-23 16:34  ademik  阅读(9)  评论(0编辑  收藏  举报