[CodeForces] CF847 题解
A. Union of Doubly Linked Lists
【题目大意】
给你若干个双向链表,让你把它们连成一条。
【解题思路】
每次把一条链表的头连向另一条的尾,用一个变量维护一下链表的尾,直接做就做完了。
B. Preparing for Merge Sort
【题目大意】
给定一个元素互不相同序列 \(a\),每次可以取出 \(a\) 中最长的一个上升子序列,但要求包含 \(a\) 的第一个数,然后将这个子序列删掉。求每次取出来的数。
【解题思路】
我们维护每次取出来的子序列的末尾值 \(f\)。
显然,这个值是单调递减的。因为如果有 \(f_i < f_j, i < j\),那么取第 \(i\) 条子序列时可以将 \(f_j\) 取走。
所以,对于数 \(a_i\),如果当前子序列一共有 \(l\) 条,分两种情况考虑:
-
若 \(a_i \leq f_l\),如果 \(a_i\) 比最小的末尾值还小了,这意味着,没有子序列可以在 \(a_i\) 加入后保持单调递增。这时,我们给 \(a_i\) 新开一个子序列。
-
否则,\(a_i\) 可以加到子序列里。为了维护单调性,我们需要找到一个位置,使得 \(a_i\) 加入后,\(f\) 依然单调递减。形式化地,我们需要找到一个位置 \(j\),使得 \(f_{j - 1} > a_i\) 且 \(a_i > a_j\),然后将 \(a_i\) 插入到第 \(j\) 条子序列的后面,并更新 \(f\) 数组。注意到 \(f\) 具有单调性,二分查找即可。
统计答案使用一个 vector。直接做就做完了。
C. Sum of Nestings
【题目大意】
称一个字符串为括号序列,当且仅当它仅由 (
或 )
构成。
称一个括号序列是合法的,有
- 空串是一个合法括号序列
- 如果 \(s\) 是合法括号序列,那么 \((s)\) 也是。
- 如果 \(p\) 和 \(q\) 都是合法括号序列,那么 \(pq\) 也是。
以上定义与你熟知的定义相同。
在一个合法的括号序列中,称一对括号有 \(t\) 对嵌套,当且仅当在这对括号之间有 \(t\) 对括号。
称一个合法的括号序列 有 \(t\) 对嵌套,当且仅当对于这个序列的每一对相互匹配的括号,它们的嵌套对数之和为 \(t\)。
例如,合法的括号序列 ()(())
有 \(1\) 对嵌套,而 (((())))
有 \(6\) 对嵌套。
现在,你需要构造一个合法的括号序列,使得它一共有 \(n\) 对括号,\(k\) 对嵌套。
【解题思路】
注意到每次对于一个有 \(t\) 对括号的合法括号序列 \(s\) 中,括号序列 \((s)\) (即在 \(s\) 外面加一对括号)会比原序列 \(s\) 多 \(t\) 对嵌套,多 \(1\) 对括号。而括号序列 \(s()\)(即在 \(s\) 后面加一对括号)会比 \(s\) 多 \(1\) 对括号,但嵌套对数不变。
这样我们就有一种构造方案:
欲构造有 \(n\) 对括号,\(k\) 对括号嵌套的合法括号序列 \(s\):
- 若 \(n - 1 \leq k\)。记有 \(n - 1\) 对括号,\(k - n + 1\) 对括号嵌套的合法括号序列为 \(s^{\prime}\)。则有 \(s=(s^{\prime})\)。
- 否则,记有 \(n - 1\) 对括号,\(k\) 对括号嵌套的合法括号序列为 \(s^{\prime}\)。则 \(s=s^{\prime}()\)。
构造的可行性显然。
这样,我们成功地将构造 \(s\) 的问题转化为构造 \(s^{\prime}\) 的问题,通过递归不难实现,直接做就做完了。
D. Dog Show
【题目大意】
\(n\) 盆狗粮编号为 \(1\) 到 \(n\),它们从左到右排成一排,数轴上位置为 \(1\) 到 \(n\)。第 \(i\) 盆狗粮,只有在 \(t_i\) 秒以后才能吃,吃了它获得的价值为 \(1\)。狗从数轴原点开始,每次移动 \(1\) 单位长度需要 \(1\) 秒,狗可以选择不吃,可以在原地停留或者往右走,求在 \(T\) 秒内能获得的最大价值(第 \(T\) 秒不能吃)。
【解题思路】
神仙贪心。
注意到这题有一个很好的性质:所有狗粮的价值都一样。
首先,对于第 \(i\) 盆狗粮,吃掉它需要在它这里停留 \(\max{(t_i - i, 0)}\) 秒,因为移动到它需要 \(i\) 秒,这样剩下的时间就是停留的时间。
但是,我们最多有 \(T\) 秒,所以狗最多在那里停留 \(T - i - 1\) 秒。为什么减 \(i\)?因为需要花费 \(i\) 秒移动到那里;为什么减一?因为第 \(T\) 秒不能吃。
那么为什么要计算停留时间呢?对于一个狗粮,如果要停留,显然不管在哪里停留都一样(当然不能是在该狗粮后面),于是我们只在意停留时间。
好,我们这里先说做法,等会再解释。
具体地,我们对于第 \(i\) 个狗粮,显然对于第 \(1\) 到 \(i - 1\) 个狗粮,如果停留时间超过了 \(T - i - 1\) 那么就不能吃,否则就能吃。
注意到我们在枚举 \(i\) 时,\(T - i - 1\) 是递减的。于是,我们可以用大根堆来维护停留时间。如果堆顶大于 \(T - i - 1\) 那么就弹掉,直到堆顶小于这个值,然后再把在第 \(i\) 个狗粮停留的时间扔堆里。这时候,堆的大小就是现在的答案。总答案是所有这些答案的最大值。
好,那么现在有人会问:我现在把所有大于 \(T - i - 1\) 的停留时间都弹掉了,但是剩下的停留时间的和可能大于 \(T - i - 1\),怎么办?
这个事情是这样的。我们总共的停留时间不是求和,而是求最大值。因为我们在前面的狗粮停留时,间接地,我们也等待了后面的狗粮。因为对于每个狗粮,时间流逝是一样的。其实这就是一个木桶原理(仔细读读题目,如果想看详细的去看 luogu 的)。
好了,这样真的直接做就做完了。这道题是道蓝题,代码只有 19 行。
E. Packmen
咕
F. Berland Elections
咕
G. University Classes
【题目大意】
给定 \(n\) 个长度为 \(7\) 的字符串,统计每一列 \(1\) 的个数。
【解题思路】
暴力统计即可,直接做就做完了。
H. Load Testing
【题目大意】
给一个数组 \(a\),问多少次对单个位置 \(+1\) 操作后,能将序列变成前一段严格递增,后一段严格递减(即单峰序列)。
【解题思路】
考虑维护两个数组 \(p_i\) 与 \(q_i\),分别表示前 \(i\) 个数为严格递增或第 \(i\) 个数到第 \(n\) 个数为严格递减时位置 \(i\) 的最小值。
考虑计算这两个数组。对于前 \(i\) 个数,考虑正序递推。由于它们是严格递增,所以 \(p_i\) 最小为 \(p_{i - 1} + 1\)。但是只有 \(+1\) 操作,所以如果 \(p_{i - 1} + 1 < a_i\),那么就有 \(p_i = a_i\)。所以有递推式
同理,\(q\) 倒序递推即可。有递推式
考虑枚举最高点 \(i\)(即山峰),对于 \(i\) 前面的数可以前缀和计算需要几次 \(+1\),对于 \(i\) 后面的数后缀和计算,对于 \(i\) 这个数,取到的值为 \(\max{(p_i, q_i)}\),因为 \(i\) 既属于前面的严格递增序列,也属于后面的严格递减序列。这样直接做就做完了。
形式化的:
记 \(sa\)、\(sb\) 分别为 \(a\) 的前缀和和后缀和数组,则有
记 \(sp\)、\(sq\) 分别为 \(p\) 的前缀和数组和 \(q\) 的后缀和数组,则有
对于最高点 \(i\),有答案为
注意需要特判整个序列严格单增或者严格单减的情况,有答案为
即
这样就做完了。
I. Noise Level
咕
J. Students Initiation
咕
K. Travel Cards
咕
L. Berland SU Computer Network
咕
M. Weather Tomorrow
【题目大意】
给定一个 \(n\) 个数的数列,如果它为等差数列输出第 \(n + 1\) 项,否则输出第 \(n\) 项。
【解题思路】
注意到对于等差数列 \(a\) 有 \(2 \times a_i = a_{i - 1} + a_{i + 1} (2 \leq i < n)\),直接做就做完了。