CSP-S 历年题集
I 2019
D1 T1 格雷码
简单模拟,翻转只需减一下即可。
D1 T2 括号树
我们令 \(s_x\) 表示以 \(x\) 点为结尾所能构成的合法序列的方案数,则我们可以在树上括号匹配,若点 \(x\) 为右括号且匹配的左括号为 \(u\) 点,则有 \(s_x = s_{fa_u} + 1\),最后每个节点的答案即为树上前缀和。
D1 T3 树上的数
贪心 + 思维。部分分对于正解有启发作用。
暴力 10pts。
首先我们考虑贪心,从小到大枚举每一个数字,尽可能的让每个数字到达的点编号最小,所以我们只需要考虑是否可以使某个数字从 \(u\) 到 \(v\) 即可。
从菊花图开始,可以发现,删边顺序使节点间构成了一个环,我们可以用并查集维护这个环。
链的部分比较难,对于一个点最多只有三种删边情况,即 先删左,先删右,未删,对于一个 \(u \rightarrow v\) 的路径,不妨设 \(u < v\),我们发现。
- 对于 \(u\),需要满足该点必须为先删右。
- 对于在 \(u,v\) 中间的节点 \(p\),需要满足该点必须先删左。
- 对于 \(v\),需要满足该点必须为先删右。
这样我们可以 \(\mathcal{O}(n)\) 判断是否可以满足条件,结合贪心即可。
对于一般的树,对于每个节点,相当于我们有一些先后关系,需要判断是否满足条件。不像链一样,我们只有少数情况,这些先后关系是及其复杂的。
这种先后关系我们可以用并查集/链表维护。
假设我们要 \(u \rightarrow v\),我们逐个讨论:
- 对于 \(u\),需要满足这个路径上的第一条边 \(w\) 是该点最先删除的。详细一点,需要满足:
- 该点最先删除的边为 \(w\)。
- 不能有边在其前面删除。
- 不能在已经维护好起点与终点所有顺序关系后还存在边未被删除。
- 对于 \(v\),需要满足这个路径上的最后一条边 \(w\) 是该点最后删除的。即:
- 该点最后删除的边为 \(w\)。
- 不能有边在其之后删除。
- 不能在已经维护好起点与终点所有顺序关系后还存在边为被删除。
- 对于 \(u,v\) 中间节点 \(p\),该路径上的两条边 \(w1\) 与 \(w2\) 的先后顺序是必须相邻且顺序的。即:
- \(w1\) 之后的不能有边,\(w2\) 之前不能有边。
- \(w1\) 不能是最后删边,\(w2\) 不能是最先删边。
- \(w1\) 与 \(w2\) 不能已经被删边。
- 不能在已经加入两边后,使得维护好起点与终点顺序关系后还存在边未被删除。
这样我们从小到大枚举数字,再从小到大枚举节点,判断是否可行,这样复杂度是 \(\mathcal{O}(n^3)\)。
只需要以某个点为根,遍历整棵树,找出符合要求的最小节点编号,这样复杂度是 \(\mathcal{O}(n^2\log{n})\) 的。
细节多,思路厉害,是好题。
D2 T1 Emiya 家今天的饭
限制 \(3\) 比较强,可以发现一个性质:若有满足不符合要求的方案,则有且仅有一种主要食材不符合要求。则我们可以求出不符合要求的方案数,总方案数减去可得答案。
这样我们枚举主要食材为 \(w\),让其作为不符合要求的食材。
则我们设 \(f_{i,j,k}\) 表示前 \(i\) 种烹饪方式中,选用了 \(j\) 种烹饪方式(满足性质 \(2\)),且其中有 \(k\) 种是用 \(w\) 烹饪的。
则有转移方程 \(f_{i,j,k} = f_{i-1,j,k} + f_{i-1,j-1,k} \times (s_i - a_{i,w}) + f_{i-1,j-1,k-1} \times a_{i,w}\),其中 \(s_i = \sum a_{i,j}\)。
则不符合方案数即为 \(k > \left\lfloor \frac j 2\right\rfloor\) 的 DP 值,这样复杂度是 \(\mathcal{O}(mn^3)\),84pts。
我们考虑优化,可以发现,我们不关心 \(j\) 与 \(k\) 的真实值,我们只关心是否 \(k > \left\lfloor \frac j 2\right\rfloor\)。移项得 \(2 \times k - j > 0\),即我们只关心这个值,我们可以消减状态,设 \(f_{i,u}\) 表示前 \(i\) 中烹饪方式中,使得 \(2 \times k - j = u\) 的方案数。
则有转移方程 \(f_{i,u} = f_{i-1,u} + f_{i-1,u+1} \times (s_i - a_{i,w}) + f_{i-1,u-1}\times a_{i,w}\)。
复杂度 \(\mathcal{O}(mn^2)\) 可过,注意 \(u\) 可能为负数,需要加一个偏移量。
D2 T2 划分
首先有 \(\mathcal{O}(n^3)\) 的简单 DP,不过与正解无关。
对于 \(s_1 \leq s_2\),当 \(s_2\) 最小时,\(s_1^2 + s_2^2\) 最小。
这样我们设 \(f_i\) 表示选择 \([f_i+1,i]\) 中的数组成一组数据,可以取得最小贡献,则我们可以贪心的选择尽可能靠右的决策点,可以 \(\mathcal{O}(n^2)\) DP。
符合要求的决策点有 \(s_i - s_j \geq s_j - s_{f_j}\),即为 \(s_i \geq 2 \times s_j - s_{f_j}\)
我们可以单调队列优化,复杂度 \(\mathcal{O}(n)\),不过输入真逆天。
D2 T3 树的重心
我们考虑每个节点 \(x\) 所造成的贡献,设删去一条边所减去的节点数为 \(S\),则我们需要分讨是否在节点 \(x\) 的最大子节点内。
这样是不好做的,我们考虑选择一个节点作为根,来去除这些麻烦,我们需要使最大节点固定,这样我们可以选择以原树的重心为根,这样除根以外的其他节点的最大节点都朝向根,即对于这些节点 \(x\),删除其子树内的边不可能造成该点的贡献,这样我们就方便了许多。
这样我们对于除根以外的点 \(x\),要使 \(x\) 节点为根,需要满足 \(2\times s_x \leq n - S\) 以及 \(2\times (n - siz_x - S) \leq n - S\) 其中 \(s_x\) 表示 \(\max\limits_{y \in x}siz_y\)。
移项可得 \(n - 2\times siz_x \leq S \leq n - 2\times s_x\)。
则我们只需要用树状数组求出即可,而对于 \(x\) 子树内的边可以用树状数组在进出该点时相减一下即可,减去这些贡献即可。
最后我们只需要暴力考虑根节点所造成的贡献即可,即分讨一下再判断即可。
复杂度 \(\mathcal{O}(Tn\log{n})\)。
II 2019 江西重赛
T1 日期
暴力分讨即可。
T2 和积和
我们考虑枚举 \(i\),设当前 \(s_i\) 表示 \(r = i\) 所有 \(l \in [1,i]\) 的和,可以发现,当我们 \(i\) 增加时,相当于 \(A \times B \rightarrow (A + a_i) \times (B + b_i) = AB + Ab_i + a_iB + ab\)。
我们考虑每个式子,首先有 \(AB = s_{i-1}\),\(A\) 即为所有前面 \(a\) 的和的和,\(B\) 同理,\(ab\) 共出现了 \(i\) 次(因为有 \(i\) 个式子)。
则有 \(s_i = s_{i-1} + b_i \times \sum_{j < i} {j \times a_j} + a_i \times \sum_{j < i}{j \times b_j} + i \times a_i \times b_i\)。
简单维护即可,复杂度 \(\mathcal{O}(n)\)。
T3 网格图
考虑 Kruskal 的本质,即为贪心枚举边权,以及防止成环,则我们可以 \(a,b\) 排个序,对于横线,我们考虑那些边不能连,可以发现是与 当前已加竖线条数 相关的。竖线同理。
复杂度 \(\mathcal{O}(n\log n)\)。
T4 散步
我是历史学家,这就是史。
代你码
T5 多叉堆
考虑对于一棵树 \(x\),新加入一个子树 \(y\) 的贡献,首先需要满足 \(x\) 节点最小,可以发现这些 \(size \in [0,size_x + size_y)\) 是等价的,即它们只有大小关系,具体数值是不重要的,所以我们可以得出 \(f_x = \dbinom {size_x + size_y - 1} {size_y} f_y f_x\),即在这些数中选 \(size_y\) 个分配给 \(y\) 子树。
对于合并可以并查集维护。
复杂度 \(\mathcal{O}(n\alpha(n))\)。