CFR-744-Div.3解题报告

赛时 AC 2道题,掉大分(哭)

A. Casimir’s String Solitaire

题目传送门

ProblemProblem

给你一个仅含 A,B,C 的字符串,每次可以删掉一个 A 和一个 B,或一个 B 和一个 C,位置、顺序不限,问能不能删完。

t1000,len50t\le 1000,len\le 50

SolutionSolution

大水题,只需要判断 A 的数量加 C 的数量是否等于 B 的数量。一开始脑抽还判断 A 的数量是否等于 C 的数量

B. Shifting Sort

题目传送门

ProblemProblem

定义对一段区间的 Cyclically Shift(以下简称Shift) 操作为:

  1. 指定一个数 x(xlen)x(x\le len) 为操作的周期。
  2. 每次将区间左移一位,移出去的那一位放到最右边,重复 xx 次。

给你一个数列 aa,问如何用不超过 nnShift 操作将 aa 排好序(不要求使用次数最少,只要不超过 nn 就行)。

1t1000,2n501\le t \le 1000,2\le n\le 50

SolutionSolution

注意只要求不超过 nn 次,也就意味着我们只需要每一次把一个数排好序就行了。我们可以每次挑选最大的数,通过一次 Shift 操作(x=1x=1)将它移到最右边的位置,如果已经在该在的位置就不操作,每次都能将一个数归位,重复 nn 次即可。

eg.

1
2
3
4
5
6
7
8
原序列
2 5 1 4 3
将5归位
2 1 4 3 5
将4归位
2 1 3 4 5
将2归位
1 2 3 4 5

由于 nn 很小,暴力找最大值就可以。

C. Ticks

题目传送门

ProblemProblem

给你一个 n×mn\times m 的网格图,每个格子有 *. 两种状态,* 表示填,. 表示不填,问能不能通过若干个大小超过 kk 的“V字形”表示出这个图形(V 的两条边必须一样长,机房的两位大佬就是没判断这个而 FST 了)。

“V字形”大小的定义:

1
2
3
*...*
.*.*.
..*..

的大小为 22

1kn10,1m191\le k\le n\le 10,1\le m\le 19

SolutionSolution

注意到 nnmm 的范围很小,完全可以通过暴力求解。对于每一个格子,尽可能多的往上延伸,如果超过 kk 就把覆盖格子的标记一下,最后判断是否都被覆盖完。

D. Productive Meeting

题目传送门

ProblemProblem

在一场见面会中有 nn 个人,会议开始后他们会两两交谈,每个人有一定的耐心值 aia_i,第 ii 个人在交谈 aia_i 次后会离开会议,两个人可以交谈多次,请找出一种方案使得总交谈次数尽可能多。

1t1000,n2×105,ai2×1051\le t\le 1000,\sum n\le 2\times 10^5,\sum a_i\le 2\times 10^5

SolutionSolution

由于 ai\sum a_i 不大,我们可以依次考虑每一次交谈,容易想到每次让耐心值最大的两个人交谈是最优方案。

实现 1

先排好序,每次让剩余耐心值最大的两个人交谈,耐心值–,在考虑维护序列单调性,可以通过一通 lower_boundupper_bound 以及 swap 来实现,时间复杂度 O((ai)log(n))O((\sum a_i)\log(n))

实现 2

使用 lower_boundupper_bound 来维护需要考虑一大堆细节(我调错调了一下午加一晚上),不如用堆来维护。每次从堆里拿出两个耐心值最大的人,耐心值–,如果还有剩余耐心值,就把他们再扔回堆里,用 STL 的优先队列实现非常简洁,时间复杂度也是 O((ai)log(n))O((\sum a_i)\log(n))

E1. Permutation Minimization by Deque

题目传送门

在 Codeforces 中首次被 hack 祭。

ProblemProblem

给你一个 1n1-n 的排列,你需要把它们按顺序扔进双端队列里,你可以决定从哪一端扔。需要使得最终双端队列里的数的字典序最小。

1t1000,n2×1051\le t\le 1000,\sum n\le 2\times 10^5

Solution 1Solution\ 1

由于要让字典序最小,肯定最小的值放在最前面,最小值之前的数的放法先不管,放完最小值之前的数之后在把最小值放在最前面,最小值后面的数就只能从后面挨个放了。而最小值之前的数我们可以递归处理。

具体实现中我们需要用 ST 表维护区间最小值,再用分治递归的方法实现。

Solution 2Solution\ 2

从通过人数上看,这道题的简单程度可是仅次于 A 题,怎么会这么复杂呢?

考虑用贪心的思想,先扔进去第一个数,以后对于每一个数,如果它比队首小,就扔到队首(这样可以让结果的字典序尽可能小),否则就扔到队尾(如果还扔到队首字典序就大了)。就是这么简单。

E2. Array Optimization by Deque

题目传送门

ProblemProblem

给你一个长度为 nn 的数列(注意不是排列),你需要把它们按顺序扔进双端队列里,你可以决定从哪一端扔。需要使得最终双端队列里的逆序对尽可能少。

1t1000,n2×105,109ai1091\le t\le 1000,\sum n\le 2\times 10^5,-10^9\le a_i\le 10^9

SolutionSolution

同样是贪心,对于每个数,如果放在队首,则贡献的逆序对数为前面比它小的数的个数,反之则为比它大的数的个数,这个数放在队首还是队尾对以后的方法不会产生干扰,所以只需要判断它前面是比它大的多还是比它小的多,这可以用树状数组或权值线段树维护。由于 aia_i 的值跨度过大,需要先进行离散化处理。