前言
CSP 2022-03 算法题解析
未初始化警告
链接:http://118.190.20.162/view.page?gpid=T143
- 时间限制:1.0s
- 空间限制:512.0MB
问题解析
很简单的模拟题,注意 \(a_0\) 是常量不需要初始化。
运行结果
提交编号 | 用户名 | 姓名 | 试题名称 | 提交时间 | 代码长度 | 编程语言 | 评测结果 | 得分 | 时间使用 | 空间使用 |
---|---|---|---|---|---|---|---|---|---|---|
* | * | * | 未初始化警告 | 09-17 19:38 | 363B | CPP14 | 正确 | 100 | 93ms | 3.328MB |
Cpp代码
1 |
|
出行计划
链接:http://118.190.20.162/view.page?gpid=T142
- 时间限制:1.5s
- 空间限制:512.0MB
问题解析
很简单,根据出行时间和核酸结果所需时间可以推算出所需核酸时间段,要查询某个时间点在多少个时间段内,只需创建一个差分数组,因为查询是单调递增的所以遍历差分数组维护前缀和即可,更好一点的方法是使用有序结构来作为差分数组代替差分数组。实际上出行时间有没有顺序无所谓,但查询要求是有序的。
运行结果
前面三次错误都是只设置了
1e5
的数组偏移值,实际上范围是2e5
所以一直报错第一行是使用有序结构(实质是红黑树)插入总时间是 \(O(n \log n)\) 但查询是 \(O(n)\) 的.
后面四行时间比起前一点的是差分数组,插入时间是 \(O(n)\) 但查询是 \(O(C)\) 的,这里 \(C = 10^6\) (这里稍微设置大了一点,其实 \(5\times 10^5\) 应该也是够用了) .
实质上 \(n\) 和 \(C\) 是一个数量级的所以其实直接用个大一点的数组反而更快
提交编号 | 用户名 | 姓名 | 试题名称 | 提交时间 | 代码长度 | 编程语言 | 评测结果 | 得分 | 时间使用 | 空间使用 |
---|---|---|---|---|---|---|---|---|---|---|
出行计划 | 09-17 21:05 | 797B | CPP14 | 正确 | 100 | 390ms | 8.925MB | |||
* | * | * | 出行计划 | 09-17 20:56 | 750B | CPP14 | 正确 | 100 | 296ms | 6.742MB |
* | * | * | 出行计划 | 09-17 20:53 | 750B | CPP14 | 运行错误 | 0 | 15ms | 21.94MB |
* | * | * | 出行计划 | 09-17 20:49 | 738B | CPP14 | 运行错误 | 0 | 15ms | 21.94MB |
* | * | * | 出行计划 | 09-17 20:48 | 738B | CPP14 | 运行错误 | 0 | 15ms | 41.01MB |
C++代码
1 |
|
使用 有序结构 代替差分数组,看运行时间还慢了 100 ms 主要是因为插入慢了些
1 |
|
计算资源调度器
链接:http://118.190.20.162/view.page?gpid=T141
- 时间限制:1.0s
- 空间限制:512.0MB
问题解析
大模拟题,有空再补上吧
运行结果
提交编号 | 用户名 | 姓名 | 试题名称 | 提交时间 | 代码长度 | 编程语言 | 评测结果 | 得分 | 时间使用 | 空间使用 |
---|---|---|---|---|---|---|---|---|---|---|
代码
通信系统管理
链接:http://118.190.20.162/view.page?gpid=T140
- 时间限制:2.0s
- 空间限制:512.0MB
问题解析
开始想的是对每个计算机都用 map 来存
运行结果
C++
1 |
|
博弈论与石子合并
链接:http://118.190.20.162/view.page?gpid=T139
- 时间限制:1.0s
- 空间限制:512.0MB
问题解析
首先题目不难理解,就是足够聪明的小c要使最后一堆石子数最少,绝顶聪明的小z要使最后一堆石子数最多,两人轮流操作,要么合并,要么扔掉最左边或者最右边。
大家沉浸式想象一下,我们担任小c或者小z中的一员,来体验这个游戏。假设我们就是小z,要尽可能保留最后一堆的石子数最大,但是我们的对手是小c,他不断干扰我们,欲使我们的石子数最少,那我们现在对这个问题的求解就有了新的定义,即要求出最少的最大石子数,最少是前提条件(小c的干扰),最大是我们的任务(小z的任务)。
模拟场景一:我们面前有偶数堆的石子,我们(小z)先操作(k==1
),我们肯定会先合并最中间的两堆石子,再静观其变,如果小c扔掉最左边的石子堆,那我们就靠右合并,如果小c扔掉最右边的石子堆,那我们就靠左合并,这样目的是为了时刻保持我们合并的石子堆在最中间,以防被小c扔掉,这样就能保证我们合并的石子数是最大的。如果我们合并的石子堆不是在最中间,就算合并的数量再多,最后还是会被小c扔掉,到头来白打工了。当然,足够聪明的小c也知道你会这么做,他也会控制着自己每次扔掉的是最左边还是最右边,以此来使得你最后合并的数量最小,以此来转化成求解问题,即最小的相邻数段和(因为每次合并都要求是相邻的)。同理,当面对奇数堆的石子,小c先操作(k==0
)时,我们已经处在一个最中间的状态,小c扔左,我们合并右,小c扔右,我们合并左。
1 |
|
模拟场景二:当我们面对奇数堆的石子,我们(小z)先操作(k==1
)或者我们面对偶数堆的石子,小c先操作(k==0
)时,即轮到我们(小z)操作的时候,我们面对的永远是奇数堆(因为小c不管是合并还是扔掉,都会是总数减1),我们本已处在最中间最安全的位置,由于我们的操作,会使合并的石子堆位于偏左或偏右的状态,这对于我们来说就是不安全、危险的位置,因为一旦小c发觉你合并的数量多的时候,他就想方设法把你合并的石子堆扔掉。因为你无论怎么合并,小c总有办法把你合并的给扔掉,这样就不能保证合并的石子堆最大并且保留到最后。那怎样才能使得最后的石子堆最大呢?我们知道,当我们面对这种场景二时,小c的操作步数是n/2,即小c只能合并或者扔掉(n/2)次。如果这些个石子堆中有大于(n/2)个x,则小c无论怎样都不能扔完(就算他先合并再扔也相当于操作两次扔两堆),此时能保留到最后一堆的石子数至少有x,所以我们场景二的任务就是要找到最大的那个x,即刚好能满足大于(n/2)的x(刚好等于(n/2)不行,这样会刚好被扔掉)。
1 | bool check(int x, int n)//x的判断 |
运行结果
提交编号 | 用户名 | 姓名 | 试题名称 | 提交时间 | 代码长度 | 编程语言 | 评测结果 | 得分 | 时间使用 | 空间使用 |
---|---|---|---|---|---|---|---|---|---|---|
代码
1 |
|