CSP2019 题解

D1T1 格雷码(code)

题目传送门

https://loj.ac/problem/3208

题解

按照题意模拟就可以了。

对于第 \(i\) 位,如果 \(k \geq 2^i\) 那么这一位就是 \(1\),然后把 \(k\) 变成 \(2^{i + 1} - k - 1\)。否则这一位为 \(0\),\(k\) 不变。

代码

https://loj.ac/submission/687508


D1T2 括号树(brackets)

题目传送门

https://loj.ac/problem/3209

题解

考虑在每一个点 \(i\) 处求出从根到 \(i\) 的括号序列中的所有后缀的合法数量 \(f_i\),其余的子串的贡献可以直接从父亲处得到。

维护一个栈存储从根到 \(i\) 的没有被匹配的左括号的位置 \(x\),那么显然如果 \(i\) 上是右括号,那么 \(f_i = f_x + 1\),否则 \(f_i = 0\)。

记得在每一个点的处理中记录被弹掉了哪个点,方便回溯。

代码

https://loj.ac/submission/687509


D1T3 树上的数(tree)

题目传送门

https://loj.ac/problem/3210

题解

作为从根本上把 CSP 难度推向弱胜省选难度的题目,这道题需要分成好几块来讲。

菊花图

菊花的部分分很简单(我又没想出来)。

很容易发现把某一个连接根的边断掉以后,这个点的点权会和根交换,于是这个点的点权就变成了上一个被断的边的点权。

于是可以发现所有的点之间存在这样的关系:

\[
\text{根} \to v_1 \to v_2 \to \cdots \to v_{n - 1} \to \text{根}
\]

也就是说,点权的移动形成了环的关系。我们只需要构造出这个环。

维护很多个链,从小到大枚举每一个点权,找到对应的点,它应该连向目前是链底的一个点中编号最小的点。注意只有在一条链的点数已经满了的时候才可以形成环。

这个可以用并查集或者把链缩成"链底 \(\to\) 链顶"的格式来维护。

这个部分分的代码:https://loj.ac/submission/687489 的 Task2。

在链上,如果想要把 \(x\) 上的点权移动到 \(y\),那么需要满足如下条件:

  • 那么对于 \(x\):两个邻边中朝向 \(y\) 的边必须是第一个断掉的。

  • 对于中间的点:两个邻边中朝向 \(x\) 的边必须要比 \(y\) 先断。

  • 对于 \(y\):两个邻边中朝向 \(x\) 的边必须是最后一个断掉的。

于是我们只需要维护每个点的两个邻边的断边顺序即可。从小到大枚举点权,从对应的点上来一次 \(dfs\),可以一边扫一遍判断合不合法,找到最小的可以移动到的点就可以了。

这个部分分的代码:https://loj.ac/submission/687489 的 Task3。

Full

可以发现,对于一个点来说,和菊花类似,以它为根的整棵树中,每一个子树中的点权的去往顺序也依然是形成了一个链的关系:
\[
\text{根} \to v_1 \text{的子树} \to v_2 \text{的子树} \to \cdots \to v_{n - 1} \text{的子树} \to \text{根}
\]
这个链的关系既是点权的移动顺序,也可以表示删边顺序,就是先删 \(v_1\),再删 \(v_2\)……

对于一条路径 \(x \to y\),要把 \(x\) 上的点权移动到 \(y\),那么和链类似,我们可以做出如下的限制:

  • 对于 \(x\):邻边中朝向 \(y\) 的边必须是第一个断的;

  • 对于中间的点:领边中朝向 \(x\) 的点必须恰好在 \(y\) 前一个断。
  • 对于 \(y\):领边中朝向 \(x\) 的边必须是最后一个断的。

我们考虑如何用上面的链的关系来表达断边顺序:

  • \(e\) 是第一个断的:\(rt \to e\);

  • \(e\) 是最后一个断的:\(e\to rt\);
  • \(e_1\) 恰好比 \(e_2\) 前一个断:\(e_1 \to e_2\)。

于是我们就可以对于每个点维护一堆链表来操作,和菊花一样,同样是只有在链满了的时候才可以形成环。

代码

https://loj.ac/submission/687959


D2T1 Emiya 家今天的饭(meal)

这道题没做出来是我一辈子的耻辱。

题目传送门

https://loj.ac/problem/3211

题解

看上去就很像容斥对吧。

如果我们不考虑“每种主要食材至多在一半的菜(即 \(\lfloor \frac k2 \rfloor\) 道菜)中被使用”的限制的话,那么这个题目显然就是每种烹饪方法的可以做出来的菜的数量 \(+1\) 的乘积再 \(-1\)。

想要如果解决这个限制可以考虑容斥。一半这个特殊的限制非常优美,它使得容斥只需要进行一层就可以了(因为不存在有两个食材同时超过一半)。

于是我们枚举哪一个食材超过了一半,假设这种食材为 \(A\)。那么我们维护这样的东西 \(dp[i][j][k]\) 表示前 \(i\) 个烹饪方式中,其中 \(j\) 个烹饪方式用了食材 \(A\),\(k\) 个没有使用的方案数。\(dp\) 的时候直接类似 \(01\) 背包转移就可以了。

最终的限制条件就是 \(j > k\)。

但是这样做是 \(O(mn^3)\) 的。可以获得 \(88pts\)。

因为我们只需要保证 \(j > k\) 即 \(j - k > 0\),所以我们可以直接维护 \(j - k\) 而不是分开维护 \(j\) 和 \(k\)。

时间复杂度 \(O(mn^2)\)。

代码

https://loj.ac/submission/687509


D2T2

题目传送门

https://loj.ac/problem/3212

题解

并不会证明,只能抽象理解。

可以发现每一个数的贡献就是要乘上它的所在段的和。所以我们要尽量最小化每一段的和,也就是尽量最小化最后一段的和(因为和是递增的)。

然而这个理解方式非常不严谨。

也许可以这样考虑:

把一个子段划分为两段,如果存在两种可以行的划分方式:前面一段的和为 \(s_1\),后面一段的和为 \(s_2\),中间夹着一个数 \(a\),我们考虑应该把 \(a\) 放进前面还是后面。其中 \(s_1 + a \leq s_2\)。

于是
\[
(s_1 + a)^2 + s_2 ^ 2 = s_1^ 2 +s_2 ^ 2 +2as_1 + a^2\\
s_1^2 + (a + s_2)^2 = s_1 ^ 2 + s_2 ^ 2 + 2as_2+a^2
\]
因为 \(s_1 < s_2\) 所以显然选择前者更优,也就是让后面的那一段小一些更优。

然而这样考虑还是很不严谨,算了自闭了不证了。

这样我们的目标就很明确的:最小化最后一段的和。

令 \(f_i\) 表示前缀 \(1..i\) 的最后一段的和的最小值。转移的时候我们需要保证 \(f_j \leq s_i - s_j\) 其中 \(s_i\) 表示前缀和。

\(f_j \leq s_i - s_j\) 等价于 \(f_j + s_j \leq s_i\)。当满足这个条件时,应该尽量取 \(j\) 大的。

所以如果对于 \(j, k\) 满足 \(f_j + s_j > f_k + s_k, j < k\) 那么 \(j\) 就可以被舍弃了。

同时因为 \(s_i\) 是递增的,所以我们可以维护一个单调栈,其中只保留最后一个满足要求的 \(j\),这个 \(j\) 就是 \(i\) 的决策点。

最后因为答案爆炸了 ll,所以需要开一个 \(128\) 个字节的高精度(使用两个 \(ll\) 实现)。

但是如果直接开的话会把 \(1G\) 的空间限制开炸了,所以我们维护前面的每一个点的决策点,最后只需要用一个 \(128\) 字节的变量统计答案就可以了。

代码

我比较懒,不想写高精度,所以用了 int128(其实高精度也很好写)。

https://loj.ac/submission/687514


D2T3 树的重心(centroid)

题目传送门

https://loj.ac/problem/3213

题解

考场上想到一个非常繁琐的做法,不敢写。

因为两个联通块并的重心应该在原来的两个块各自的重心之间的链上,所以可以直接在链上二分或者倍增。

但是这样还需要特判一对东西,比如连通块不包含哪个子树啊之类的。很麻烦。

所以考场还是乖乖地写了 \(75pts\)。

后来因为我的 \(75pts\) 算法最后的二叉树内容本身就非常古怪,所以想到了一个和一个可行的正解有不小的交集的做法。

我的二叉树做法大概就是发现一个点的重心只能在这个点为整棵树的根以后的最重的儿子中,(显然)所以在完全二叉树上可以直接暴力跳(每个点深度不超过 \(\log n\))。

后来发现了一个可行的正解也用了这个思路。

既然在最重的儿子的子树里面,那么实际上对于一棵树,重心只能在那条从根连下去的重链里面。

于是我们考虑动态维护每一个点为根的重链,然后在上面倍增跳就可以了。

维护重链的时候,每次选择包括其父亲在内的点中最重的儿子作为重儿子。然后因为我们需要避开一个子树,所以顺便维护一下次重的儿子,在需要避开重儿子时使用。

代码实现中需要先预处理每一个子树的重链的倍增数组,然后换根的时候再维护一个倍增数组(这个倍增数组就可以把父亲作为重儿子)。然后在重链上倍增找到最后一个子树大超过一半的点。

(感觉我讲得语无伦次

代码

https://loj.ac/submission/687516

CSP2019 题解的更多相关文章

  1. CSP2019题解

    CSP2019题解 格雷码 按照生成的规则模拟一下即可. 代码 括号树 看到括号匹配首先想到用栈,然后又在树上就可以想到可追溯化栈. 令\(a_i=1\)表示\(i\)号节点上的括号为(,否则为), ...

  2. CSP2019 树的重心 题解

    本题当然可以通过大力讨论每棵子树的size的大小关系,然后用各种数据结构暴力维护.但是我更倾向于用一种更为性质的做法. 首先讲一下我在考场上想到的做法(没写).就是考虑换根,在换根的过程中计算每一条边 ...

  3. csp2019 Emiya家今天的饭题解

    qwq 由于窝太菜了,实在是不会,所以在题解的帮助下过掉了这道题. 写此博客来整理一下思路 正文 传送 简化一下题意:现在有\(n\)行\(m\)列数,选\(k\)个数的合法方案需满足: 1.一行最多 ...

  4. CSP2019 树上的数 题解

    题面 这是一道典型的部分分启发正解的题. 所以我们先来看两个部分分. Part 1 菊花图 这应该是除了暴力以外最好想的一档部分分了. 如上图(节点上的数字已省略),如果我们依次删去边(2)(1)(3 ...

  5. CSP2019 Emiya 家今天的饭 题解

    这题在考场上只会O(n^3 m),拿了84分.. 先讲84分,考虑容斥,用总方案减去不合法方案,也就是枚举每一种食材,求用它做超过\(\lfloor \frac{k}{2} \rfloor\) 道菜的 ...

  6. 【CSP2019】题解合集

    诈个尸 先挖坑 虽然连去都没去但还是想做做 今年貌似比去年还毒瘤啊... yrx.hjw都进了省队线tql orz (myh:没AK真丢脸 Day1T1 格雷码 Day1T2 括号树 Day1T3 树 ...

  7. 【比赛题解】CSP2019 简要题解

    D1T1 code 签到题,大家都会. 可以从高位往低位确定,如果遇到 \(1\),则将排名取反一下. 注意要开 unsigned long long. #include <bits/stdc+ ...

  8. [题解]CSP2019 Solution - Part B

    \(\text{orz}\) 一波现场 \(\text{A}\) 掉 \(\text{D1T3}\) 的神仙 D2T3 centroid Solution 考虑每个点 \(u\) 作为重心的贡献 假设 ...

  9. [题解]CSP2019 Solution - Part A

    至于为什么是 \(\text{Part A}\) 而不是 \(\text{Day 1}\) 那是因为 Day1 T3 还没改 (那这六题的 \(\text{solution}\) 就按难度顺序写吧) ...

随机推荐

  1. 1450:【例 3】Knight Moves

    1450:[例 3]Knight Moves  题解 这道题可以用双向宽度搜索优化(总介绍在  BFS ) 给定了起始状态和结束状态,求最少步数,显然是用BFS,为了节省时间,选择双向BFS. 双向B ...

  2. vue 表格组件分享

    分享一款自己写的table组件  用起来还算简单好用   (先介绍使用方法(ts版本的)) 引入组件不多说 import jTable from '../comp/comp/table/table.v ...

  3. [VBA]删除多余工作表

    sub 删除多余工作表() Dim i As Integer Application.DisplayAlerts = False For i = Worksheets.Count To 1 step ...

  4. C# 截获某个域中未捕获的异常 CLR20R3 程序终止的几种解决方案

    AppDomain.UnhandledException可以获的异常,却截不下来,求解 AppDomain.CurrentDomain.UnhandledException += CurrentDom ...

  5. 淘淘相关工具类【json,httpClient,id,FTP,exception,cookie(包括共享cookie的设置等)】

    json package com.taotao.common.utils; import java.util.List; import com.fasterxml.jackson.core.JsonP ...

  6. 分布式任务队列 Celery —— 应用基础

    目录 目录 前文列表 前言 Celery 的周期定时任务 Celery 的同步调用 Celery 结果储存 Celery 的监控 Celery 的调试 前文列表 分布式任务队列 Celery 分布式任 ...

  7. 【js】什么是函数节流与函数去抖

    函数节流 意思:节省流量,不会一直访问. | 指定时间内不执行,指定时间后执行. | 一段时间内只执行一次 场景: 比如控制游戏人物攻击,时间内就算按得很快,也只能砍一刀,过后才能砍第二刀. 搜索引擎 ...

  8. codeforces 1186C Vus the Cossack and Strings

    题目链接:https://codeforc.es/contest/1186/problem/C 题目大意:xxxxx(自认为讲不清.for instance) 例如:a="01100010& ...

  9. DG on Windows 10 S: 执行任意代码

    DG on Windows 10 S: 执行任意代码 windows 10 S版本是什么鬼? 众所周知,我们使用的是windows 10企业版 LTSC.更准确一点,CMD运行winver,我的版本是 ...

  10. 第三次实验报告&&学习总结

    实验三 String类的应用 实验目的 掌握类String类的使用: 学会使用JDK帮助文档: 实验内容 1.已知字符串:"this is a test of java".按要求执 ...