GPLT L2 题解
L2-001 紧急救援
思路:
- 首先,看到这个 \(n\) 的范围,我们要想到哪几种算法可以通过
- 朴素版 \(dijkstra\) 和 \(Floyd\) 都可以通过,但本题使用 \(Floyd\) 不好处理,所以我们选用 \(dijstra\)
- 然后我们跑一遍 \(dijkstra\) ,将所有到 \(S\) 的最短距离求出来
- 然后我们 \(dfs\) 一遍,只要走到了 \(D\) 点,就个数加 \(1\),同时更新最大的人数和路径
时间复杂度:\(O(n^2)\)
1 |
|
L2-002 链表去重
思路:
- 用
bfs
把这个完整的链表建出来,然后我们去重进行重置前后的地址即可
时间复杂度:\(O(n)\)
1 | signed main() { |
L2-003 月饼
思路:
- 贪心,我们存一下每个月饼的收益,然后从大到小排序即可
- 然后逐个选取
时间复杂度:\(O(nlogn)\)
1 | signed main() { |
L2-004 这是二叉搜索树吗?
思路:
- 首先我们假设这个树是非镜面二叉搜索树,一开始设
ok
为false
,然后我们将其从先序转换为后序,假如发现这个转换后的后序数组长度不为n
,那么就清空,将他按照镜面二叉搜索树的情况来求后续遍历 - 只要以上两种情况中的任何一种合法,就直接输出,否则输出
-1
时间复杂度:\(O(n)\)
1 | signed main() { |
L2-005 集合相似度
题目大意:
其中 \(N_c\) 是两个集合都有的不相等整数的个数:两个集合交集元素个数
\(N_t\) 是两个集合一共有的不相等整数的个数:两个集合的并集的元素个数
思路:
- 用
set
直接进行集合去重和统计个数
时间复杂度:\(O(KlogM)\)
1 | signed main() { |
L2-006 树的遍历
思路:
- 根据中序遍历和后序遍历建树,然后进行
BFS
即可
时间复杂度:\(O(n)\)
1 | signed main() { |
L2-007 家庭房产
思路:
- 将每一个家庭看作一个集合,然后用并查集来维护每一个家庭
- 在合并的过程中,由于题目要求输出家庭里最小的那个编号,那么这个最小的编号就作为祖先节点
- 然后我们遍历,求出每个家庭的信息,最后统计输出即可
时间复杂度:\(O(nlogn)\)
1 | struct DSU { |
L2-008 最长对称子串
思路:
- 用字符串 \(hash\) 来判断回文串,然后枚举左右端点即可
本题也可以参考一下升级版智乃的前缀、后缀、回文的讲解
时间复杂度:\(O(n^2)\)
1 | struct Shash{ |
L2-009 抢红包
思路:
- 直接模拟就行
时间复杂度:\(O(nlogn)\)
1 | signed main() { |
L2-010 排座位
思路:
- 用并查集维护一下朋友关系
- 然后用
set
维护一下敌对关系
时间复杂度:\(O(MlogN)\)
1 | struct DSU { |
L2-011 玩转二叉树
思路:
- 按照规则构建一颗二叉树
- 然后
bfs
的时候,将左右节点的输出顺序更换一下即可
时间复杂度:\(O(n)\)
1 | struct Node { |
L2-013 红色警报
思路:
- 统计这个图的连通分量,然后每次摧毁一个城市,在求一次连通分量;
- 如果摧毁后的连通分量大于摧毁前的连通分量数
+1
,那么,就说明,这个节点导致了这个图不连通了,那么我们就需要输出Red Alert: City k is lost!
,否则输出City k is lost.
- 如果
K
的数量等于N
,那么就说明最后就摧毁完了,输出Game Over.
时间复杂度:\(O(K \times n^2)\)
1 | signed main() { |
L2-014 列车调度
思路:
- 每次将队列的第
i
个数与目前的最大值进行比较,只要出现一个比当前值小的数,我们就把比这个数大的数删掉,这样保证是从大到小的顺序,最后只需要输出这个有序队列的剩下元素的大小-1
即可
时间复杂度:\(O(nlogn)\)
1 | signed main() { |
L2-015 互评成绩
思路:
- 按照规则模拟
时间复杂度:\(O(n \times k)\)
1 | signed main() { |
L2-016 愿天下有情人都是失散多年的兄妹
思路:
- 暴搜,统计
x
和y
相差的代数
时间复杂度:\(O(n + kD)\)
1 | struct node { |
L2-017 人以群分
思路:
- 模拟即可
时间复杂度:\(O(nlogn)\)
1 | signed main() { |
L2-019 悄悄关注
思路:
- 直接模拟,判断在不在那个关注集合就行
时间复杂度:\(O(nlogn)\)
1 | signed main() { |
L2-020 功夫传人
思路:
- 直接
BFS
或者DFS
时间复杂度:\(O(N)\)
1 | signed main() { |
L2-021 点赞狂魔
思路:
- 可以利用优先队列来存储答案,利用
map
和set
来去重,然后按规则模拟即可
时间复杂度:\(O(nloglogn)\)
1 | struct node { |
L2-023 图着色问题
思路:
- 数据范围较小,其实可以直接暴力枚举,然后
check
一下当前位置是否可行,不过我这里用了BFS
来模拟这个check
的过程 - 如果个数不是
K
直接判定为No
时间复杂度:\(O(V \times N)\)
1 | signed main() { |
L2-024 部落
思路:
- 并查集,查询集合即可
时间复杂度:\(O(N \times K)\)
1 | struct DSU { |
L2-025 分而治之
思路:
- 直接记录每个点的度(
deg
)情况即可,然后每当删除一个点就把与这些点相连的点的度数都减1
,最后判断是否其他的点的度数为0
即可,这样保证了度数为0
的点是孤立的
时间复杂度:\(O(Q \times NlogN)\)
1 | signed main() { |
L2-026 小字辈
思路:
- 两遍
dfs
,第一遍先记录族谱树的最大深度,第二遍找到最大深度的所有节点,即为辈分最小的节点
时间复杂度:\(O(N)\)
1 | signed main() { |
L2-027 名人堂与代金券
思路:
- 直接模拟即可,利用
map
和set
处理所有的顺序
时间复杂度:\(O(kloglogn)\)
1 | struct node { |
L2-029 特立独行的幸福
思路:
- 模拟,用
set
记录一下是否依赖即可,然后记录幸福数的个数
时间复杂度:\(O(nlogx)\)
1 | bool isprime(int x) { |
L2-030 冰岛人
思路:
- 利用
map
来存储维京男性和维京女性以及普通男性和普通女性的姓名 - 然后利用暴力搜索出五代以内是否有公共祖先
时间复杂度:\(O(N \times logN)\)
1 | signed main() { |
L2-031 深入虎穴
思路:
- 首先找到那个唯一入口门的位置,然后进行
dfs
即可,可以类比一下L2-026 小字辈这题,几乎一模一样,唯一的区别就是有向树找根,有向树的根的入度为0
.
时间复杂度:\(O(N)\)
1 | signed main() { |
L2-032 彩虹瓶
思路:
- 按照题目意思模拟,可以看出来就是考察的
stack
这个数据结构,只要发现存储的个数大于M
或者无法按顺序排列,就不行
时间复杂度:\(O(KN)\)
1 | signed main() { |
L2-033 简单计算器
思路:
- 利用栈按照题意模拟
时间复杂度:\(O(n)\)
1 | signed main() { |
L2-034 口罩发放
思路:
- 首先我们创建一个结构体
node
来存储每个人的个人有关信息,然后创建一个map
来存储最后一次的记录的日期,通过check
函数判断是否合法,然后按照题意模拟
时间复杂度:\(O(D \times TlogT)\)
1 | struct node { |
L2-035 完全二叉树的层序遍历
思路:
- 可以发现,题目说这是一颗完全二叉树,那么可以知道,按照完全二叉树的遍历原理进行后序遍历,先进入左右子树(编号为
index * 2
和index * 2 + 1
,即index
右移1
位,和index
右移1
位+1
),cnt
为后序遍历的位置标记,并将当前所在的后序遍历的元素,填入ans[index]
内即可
时间复杂度:\(O(N)\)
1 | signed main() { |
L2-037 包装机
思路:
- 按照题目意思模拟,那个框其实就是一个栈,夹取物品就是出栈,按照意思模拟即可,只需要注意当队列为空,就不采取任何措施
时间复杂度:\(O(n \times m)\)
1 | signed main() { |
L2-038 病毒溯源
思路:
- 其实也可以用
dfs
,求出深度最大的点即可,然后倒着找path
时间复杂度:\(O(n \times klogk)\)
1 | signed main() { |
L2-039 清点代码库
思路:
- 就是计算有多少个序列是重复的,直接用
map
维护即可
时间复杂度:\(O(n(logn + m))\)
1 | signed main() { |
L2-040 哲哲打游戏
思路:
- 模拟即可,做一个结构体来存每次的存档情况,然后按照题目意思模拟
时间复杂度:\(O(n \times k)\)
1 | struct node { |
L2-041 插松枝
思路:
tree[N]
代表每一个松针数组,bot
代表盒子,我们需要按照题目的意思模拟- 但需要特别注意的是,最后一定要把盒子清空,结束的时候,盒子里不能有任何松针
时间复杂度:\(O(N)\)
1 | constexpr int N = 1010; |
L2-042 老板的作息表
思路:
- 可以根据题意,设置起始时间
00:00:00
和终止时间23:59:59
,然后将题目所给的时间排序,然后开始匹配,当找到头部相等,就更新头部信息 \(\rightarrow\) 当前位置的结束时间,最后如果结束时间不等于这一天的最后时刻,就直接输出最后的时间到最后的时刻
时间复杂度:\(O(NlogN)\)
1 | signed main() { |
L2-043 龙龙送外卖
思路:
- 快递站是一颗树,我们求每一个节点到
root
节点的深度,然后当增加一个外卖站点(节点),我们需要走的距离为计算从 \(x\) 到 \(x\) 所在的最远祖先(第一个被访问过的祖先)的路径长度 \(\Sigma_{i=0}^{M}node_{new} - node_{last} - max(node_{i})\)
时间复杂度:\(O(N + M \times Depth_{tree})\)
1 | signed main() { |
L2-044 大众情人
思路:
- 我们设
2
个集合,分别存男性和女性编号,然后用dist[i][Fri]
来存储当前这个人i
到朋友Fri
之间的距离,然后可以使用Floyd
最短路来跑一遍,来计算每个人之间的最短距离 - 由于题目中的“异性缘”的定义规则为:我们记一个人 \(i\) 在一个异性 \(j\) 眼中的距离感为 \(D_{ij}\),将 \(i\) 的“异性缘”定义为 \(1/max_{j∈S(i)}\{D_{ij}\}\),其中 \(S(i)\) 是相对于 \(i\) 的所有异性的集合。
- 所以我们可以直接暴力枚举两个集合,然后求出当前异性缘最大的那个人的编号
时间复杂度:\(O(N^3)\)
1 | constexpr int inf = 1E9; |
L2-045 堆宝塔
思路:
- 用栈模拟圈的上下移动即可
时间复杂度:\(O(nlogn)\)
1 | constexpr int N = 10010; |
L2-046 天梯赛的赛场安排
思路:
- 用
BFS
模拟,在优先队列(大根堆)里,先分配数量多的,然后分配数量少的
时间复杂度:\(O(NlogN)\)
1 | constexpr int N = 250010; |
L2-047 锦标赛
思路:
时间复杂度:\(O(k \times 2^k)\)
1 | constexpr int N = 50, M = 1 << 20; |
L2-048 寻宝图
思路:
- 直接
BFS
搜一下即可
时间复杂度:\(O(n \times m)\)
1 | signed main() { |
L2-049 鱼与熊掌
思路:
- 直接开
m
个set
即可,假设x
和y
是询问的两个物品,那么我们只需要枚举集合x
中的人员,与y
中的相同的数量即可
时间复杂度:\(O(nlogn)\)
1 | signed main() { |
L2-050 懂蛇语
思路:
- 如果按照题目意思模拟,不考虑一句话的前面是否存在空格,就会在第二个点出现格式错误,所以我们要先将前面的空格去除,然后存储的时候,需要把前面删除的空格给补回来
时间复杂度:\(O(nlogn)\)
1 | signed main() { |
L2-051 满树的遍历
思路:
- 只需要知道一颗树怎么存以及树的前序遍历即可,没啥难的地方
时间复杂度:\(O(n)\)
1 | signed main() { |
L2-052 吉利矩阵
思路:
- 我们将问题改变为存储每一行每一列的值,其中
row[i]
和col[i]
分别表示第i
行与第i
列的和,然后我们开始暴搜
时间复杂度:\(O(N^L)\)
1 | signed main() { |