小红书文章

CSP-S 第二轮仅剩不到 20 天,弱省/中等省份如何冲刺省一

本文主要针对 CSP-S 一等奖分数线在 120-170 分波动的省份。

CSP-J/S 第二轮将于 11 月 1 号开考。在剩余的不到 20 天时间里,假如您这次的目标是稳稳拿到本省的 CSP-S 一等奖,但不追求高分,作为前算法竞赛选手以及现役教练,我将根据自己多年来的做题和比赛经验,给大家介绍一下这段时间如何针对性的进行准备,把自己会的知识和技巧稳稳地转化为分数。

首先,我想谈一谈 CSP-S 中的一道题目的分数是如何构成的

一般来说,提高级一道题目的分数构成如下:

  • 初级暴力分:阶乘复杂度或指数复杂度的枚举就能拿到的分数,T1 中这类分数可能能高达 30 分,题目位置越靠后的题这档分数就会越少。
  • 特殊性质分:例如输入的图是一棵树、树退化成一条链、序列中的数据两两不同、输入只包含题目中提到的情况的一个子集等,可设计针对性的算法得分。但注意,特殊性质分的难度差异很大,有的只要一两分钟就可以想出做法,有的苦思冥想都不知道特殊性质如何利用。
  • 中高档暴力分:经过简单分析后,发现可以以较高的多项式复杂度(比如 O(n4)O(n^4))解决掉的分数。如果进一步分析题目特点,发现可以使用数据结构或一些算法优化,有可能在此基础上得到更低一级复杂度的做法(例如降低到 O(n3)O(n^3)O(n2logn)O(n^2\log n)),从而得到更多的分数。
  • 正解分:能通过 100% 数据的做法才能拿到的分数。

然后,我们要知道,想拿 CSP-S 的一等奖,需要拿到哪些分数

  • 通过研究 CSP-S 以及 NOIP 真题,大家会发现第一题的正解考察的几乎总是 J 组知识点。如果你能完全解决掉第一题,那么后边 3 道题拿到最低档暴力分,就足够在弱省拿到省一了。
  • 如果您在中等省份,则除了最低档的暴力分之外,您还应该拿到至少两道题的性质分中档暴力分
  • 遇到 T1 较难的年份,您的目标是在 T1 拿到 60-70% 的分数,后边其他题靠初级暴力和特殊性质,最终一道题都不 AC 都可以拿到省一。

那么,为了拿到这些分数,我们应该具备怎样的水平,以及做哪些训练呢?

  • 通过研究 19 年以来的真题,我们可以发现:

    • T1 的正解的平均难度黄题简单些的绿题附近,虽然前几年有出现过蓝题 T1,但最近两年的 T1 都比较简单,属于橙题
    • T2、T3 的初级暴力分的难度为橙或黄(这里我们讨论的只是这一档分数的做法的难度,而不是整道题的难度,下同)。
    • T2、T3 特殊性质分的难度一般在黄或绿。
    • T2 中档暴力分一般是简单点的绿题的难度。
    • 上面提到的这些分数,用到的知识点绝大部分是 J 组知识点,例如二分、贪心、双指针、堆、简单 DP、DFS、BFS。
  • 因此,假如您的目标是中等或弱省 S 组压线一等奖,那么您的训练应该专注于做黄题绿题,并且应该是 J 组知识点的黄题和绿题

  • 在训练时,每道题目都应该按照比赛的要求,只能提交一次,第一次测出来是多少分就是你的成绩,这要求你在提交前进行充分的测试,包括但不限于测试题目给的大样例、手造边界情况数据、写暴力对拍。

  • 对于思维难度更高的题目或 S 组中比较复杂的知识点的题目,您近期应该多关注部分分如何去打,只要拿到了你想要的部分分,就算这个题做完了。如果你平时的能力只能场上做出一部分绿题,这个时候去研究蓝题或者更高难度的正解的收益不高。根据我的参赛和教学经验,一个人临时学到的技巧在考场上几乎不可能应用出来,并且还可能因为新学的技巧而导致考场上思维被带偏,或误认为自己能做出来某题,结果导致本来该拿的分数拿不到

  • 不要在这 20 天的时间里参与和 CSP-S/NOIP 差距比较大的比赛,例如 Codeforces、AtCoder、牛客等。OI 赛场上的比赛策略也不太适用于这类比赛,打这些比赛会打乱你平时练的节奏,很容易打崩,完了之后还会影响自己的信心。要打,就去打 OI 赛制的模拟赛。

考前这些天,你需要去记录近期训练和模拟赛时自己的失误应该复习的旧知识和技巧学到的新东西,下面我会放两个例子,展示一下具体怎么做这个事情:

手把手带的一个学生,按照我的要求,总结的近期失误表格:

题目链接 难度 标签 题解 学到的东西
T673603 绿 逆序对、树状数组、贡献法 题解+std 邻项交换次数逆序对关联很大,所以首先要想到这个作为切入点,后边的套路是容易的。
P7113 拓扑排序、__int128_t 题解 学到了怎么用 __int128_t。需要注意 __int128_t 需要模拟逐位输出,不要在关闭流同步时混用输出方式(例如 putcharcout 混用)。
P2536 绿 DP 题解 注意 DP 初始化,本题中所有的 dp[i][0]dp[0][j] 都需要初始化
T676142 绿 DP、组合数学 题解+std 赛时对拍都过了,思路也很流畅,最后挂了 30 分,原因是有个地方取模没取上,而对拍只拍了小数据,只测小数据是测不出溢出的。
CF105485I ~1900 数论、线段树 题解 gcd=0\gcd = 0 时,答案应该输出 nn,这个点被我疏忽了,之后通过对拍找到了 bug,或通过思考特殊情况也可以找到该问题。

学生在国庆时打的模拟赛的实况:

学生打完后总结的经验教训:

写了对拍但还是挂分了?CSP赛时测试方法总结

0. 前言

在信息学竞赛中,对拍是一种通过自动化比较两个程序在相同随机输入下的输出结果,来检验目标程序正确性的方法。该方法可以有效地发现很多通过手动测试难以找到的隐藏错误,是信奥赛这种 OI 赛制的比赛时必会的保命技能

相信大家从网上或者自己的信奥教练口中,都或多或少了解过对拍的重要性。有些选手在尝到了对拍的甜头之后,会错误的认为“对拍过了一定没问题”,而实际上对拍并不是万能的,仍然有一部分错误是对拍难以发现的。

在讲干货之前,先讲一个故事。我亲手带的一位学生,在国庆时报名参与了洛谷的国庆集训,在第二场模拟赛中,他想出了 T1 的正解,并且把写的正解和暴力做了对拍,场上对拍没有问题。但是,当正式出分时,我们发现他的 T1 只得了 70 分。出分后他非常的疑惑,跟我进行了一些交流,并把代码发给我看。这是一道求集合方案数的问题,答案很大需要取模输出。经过简单的分析,我发现他虽然最终的结果取模了,但在计算过程中的某个隐蔽的位置忘记了取模,这可能会导致计算过程中溢出。果然,改了这个地方之后他 AC 了这道题。本来他这场比赛能打 160 多分,但因为这个失误挂成了 130 多分。

这种“对拍 AC 提交挂分” 的情况其实是普遍存在的。当我还是竞赛选手时,我自己便亲身经历过三五次。但在最近几个月的教学中,我的学生还是第一次遇到。于是,我写了这篇文章,来盘点一下那些 “对拍也防不住的坑” ,并给大家提供一套赛时测试的 “组合拳” ,最大限度确保你能拿到的分数稳稳到手。

1. 对拍为何会“失灵”?—— 四大隐形杀手**

根据我的实战经验,对拍失效通常源于以下四类错误:

1. 对拍数据范围过小,测不出数据大时会触发的 bug

  • 场景:由于对拍时总有一个程序是暴力程序,而暴力程序本身只能处理比较小的数据范围(大了跑不出结果),所以对拍时数据生成器(gen.cpp)一般来说生成的数据也会比较小(如 n20n \le 20)。但赛时数据范围(如 n2×105n \le 2\times 10^5)会导致:
    • 整数溢出:计算中间值时少取模了一次,导致中间结果超过 int 甚至 long long 范围,即使最终答案取模也无济于事。
    • 数组越界:数组开小,小数据不越界,大数据随机访问到非法内存。经常做题的人都知道,平常做题时最常出现的数据范围是 2×1052 \times 10^5,因此很多人每做一道新题时会随手开这么大的数组。但部分题目的数据范围可能高达 5×1055 \times 10^5 甚至 10610^6,这个时候就会出现越界。
  • 案例:上面提到的学生,就是因为计算过程溢出,小数据没测出来。

2. 初始化与多组数据遗忘

  • 场景:题目说“包含多组测试数据”,但对拍时为了方便 debug,生成的数据都是 T=1T = 1 的情况。正式评测时,第二组数据会沿用第一组数据的全局变量值,可能导致答案错误。
  • 案例vector 或全局数组没有在每组数据前执行 clear()memset

3. 边界与特判疏忽

  • 场景:数据生成器很难覆盖所有边界情况,你可能会说 n=0n=0n=1n=1 这类情况多拍一会儿还是可以拍到的,但很多题目的边界并非是这样一种简单的情况,这些角落里的“魔鬼”总能精准地绕过你的对拍测试。
  • 案例:图论题中,一个经常出现的边界情况是树退化成一条链,这时候可能会把复杂度卡爆。当 n=20n = 20 时,随机生成的树是一条链的概率已经不足万分之一,更别说更大的时候了。这种数据几乎只能人工构造才能得到。

4. 复杂度误判

  • 场景:你以为你写的“正解程序”的复杂度是 O(nlogn)O(n \log n),但其实复杂度是 O(n2)O(n^2),你对拍时用 n=1000n=1000 的数据很快,但赛时大数据会让你程序超时(TLE)。
  • 案例set 的二分查找,如果使用 lower_bound(set.begin(), set.end(), key),则单次查找的复杂度为 O(n)O(n),只有使用 set.lower_bound(key) 时,单次查找的复杂度才是 O(logn)O(\log n)。多组数据测试时,使用了错误的清空方式,导致每次光清空数组的复杂度就拉满了。

2. 赛时测试“组合拳”:对拍是绝招,但不是唯一的招数

要想真正“保命”,你的测试应该至少包含以下几道防线:

第一招:测样例。除了题目 PDF 中明确给出的小样例,还可能会有以附件形式给出的大样例。有时候你写的只是一个暴力解法,所以测不了最大的样例,这是正常的,你只需要把你的程序能处理的大样例测一遍就好了。

第二招:测边界数据。首先你应该重新读题,发现题目中的边界情况,边界情况常常可以从题面的数据范围部分挖掘出,另外题面中或许会有加粗的描述,这可能也是边界情况。对于你发掘出的边界情况,每种至少手动构造 1 组数据测试。

第三招:对拍。对拍的前提是你这个题写出了两种解法,倘若你只会写这个题最暴力的做法,那么是无法对拍的。假如你一道题会写暴力和更高档的一个部分分,你就可以去对拍。对拍时,最核心的是你的数据生成程序。请确保你的数据生成程序中,每个数据的生成范围要完全符合题目的要求,比如不要题目说是非负数但你只生成正数。在第一次对拍前,请把你的数据生成程序的数据范围尽可能拉大,假如对拍测出 bug 了,再调小数据生成范围,以得到一个方便 debug 的输入

第四招:静态查错。在上面的测试都通过后,请强制自己做 3 分钟的代码审查,通读一遍代码,并思考下面几个问题:

  1. 数组大小:是否开小了(RE)?是否开得太多超过了内存限制(MLE)?
  2. 多组数据:全局变量和容器是否清空了?
  3. 数据类型:该用 long long 的地方是否都用了?1LL * a * b了吗?该取模的地方都取到了吗?
  4. 边界情况:n=0,1 时,程序会崩溃或输出错误吗?
  5. 文件读写freopen文件名是否正确?提交前是否注释掉?
  6. 调试语句:调试代码时的输出删掉了吗?

3. 总结:给你的赛时测试流程建议

最后,送你一个简单的 “提交前5分钟” 检查流程:

  1. 运行对拍:最大数据跑一组。
  2. 通过后:进行 “静态查错” ,逐条核对清单。
  3. 最终验证重新运行程序,输入样例数据,肉眼确认输出是否完全正确
  4. 提交:祈祷并相信自己的准备。

记住,对拍是你最强大的武器,但绝不是你唯一的武器。 只有将 “自动化对拍” 和**“边界情况测试”**以及 “人工静态审查” 结合起来,才能最大程度地避免非技术性失分,让你辛苦想出的算法换来应得的分数。

希望这篇文章能帮你在下次比赛中少踩坑,多得分!

模拟赛打到崩溃却没有提高?教练揭秘两大误区,让模拟赛效率翻倍!

模拟赛的意义:

  • 暴露问题,比如考试环境不熟悉、文件读写忘了写、比赛策略有问题。模拟赛的前期,暴露很多问题是很正常的,甚至是好事儿,因为你近期犯过这样的错误,吃过这样的亏,过几天正式比赛就不太会再栽一次相同的跟头。
  • 训练正确的答题节奏。

模拟赛打到崩溃却没有提高?教练揭秘两大误区,让模拟赛效率翻倍!

CSP/NOIP 冲刺期,每天泡在模拟赛里,分数却像进了冷冻层?

打一场累半死,赛后只想躺平,结果下一场还是老样子…… 如果你也感觉陷入了这种「无效循环」,那么今天这篇笔记就是为你写的。

作为带过不少学生的教练,我必须说:低效的根源,往往不在“打”的过程,而在“打”完之后的收尾工作。 避开这两个大坑,你的每一场模拟赛才能真正成为提分利器。

(长文预警,请在图片中查看)

CSP-J/S 和 NOIP 即将到来,相信各位选手们最近正在狂打模拟赛。一场比赛连续紧绷 4 小时会让人感到燃尽,赛后学生难免颓废懈怠一段时间,尤其是没打好的时候,这是人之常情。我们希望每次模拟赛后能够收获一些东西,可很多同学模拟赛刷了一套又一套,没有做好比赛的善后工作,导致打了很多比赛但分数却没有长进,这样的训练就很低效了。

作为带过不少学生的教练,我必须说:低效的根源,往往不在“打”的过程,而在“打”完之后的收尾工作。 避开这两个大坑,你的每一场模拟赛才能真正成为提分利器。

限于篇幅,这篇笔记会着重讲模拟赛后的两大误区以及正确食用姿势:

误区1:赛后不补题或瞎补题

不补题,顾名思义,就是打完就不再看这个比赛了,或听讲解或看题解懂了后却不动手实践。如果是下午考完的,当天累的不想补题很正常,但如果比赛安排得非常密集,第二天也没补题的话,后边又是新的模拟赛,这样滚雪球下去可能会直接不补了。

瞎补题,是补远超自身实际水平的题目超纲知识点题目,比如你的水平场切绿题(普及+/提高)的把握都只有五六成,现在去补紫题(省选/NOI-)的 AC 做法,就算补掉了,其需要的思维深度也不是这短短十几天能构建出来的,正式比赛考场上大概率也写不出来(有一种情况例外,就是思维难度可能只有蓝或更低,但实现有一定难度的题目,还是可以补的,提升代码能力总是对的)。你真想提升硬实力的话,在几个月前就应该去做这种难度的题了,或者等下个月比赛结束后再补。

那么,什么是有效补题?有效的补题是把赛场上不会/没来及写,但稍微跳一跳就能够到部分分或正解补掉,比如你是绿题(普及+/提高)的水平,就去补蓝题(提高+/省选-)以及更简单的题目的正解,紫题(省选/NOI-)的部分分。这些分数,你在赛场上都是有希望当场拿到的,你补了之后是能够基于你目前的水平,循序渐进搭建更深更广的思维链以及更强的代码能力。

误区2:赛后不复盘赛时发挥与策略

补题是好的,打一场比赛你终归是要有一点知识或能力上的提高的。但是你有没有想过,为啥这部分分数场上没拿到?以及,你拿到的分数,是没怎么折腾就轻松拿到的,还是思考良久或调试很久才拿到的?OI 赛制最后只打出一个分数,很多学生和家长只看最后分数如何,这样会丢失很多过程信息。

啥是过程信息呢?经常打 OI 的都知道,选手们每年正式赛之后总是喜欢写游记,而游记中的一部分就是记录赛时重要的时间点做的事情,例如采用了怎样的做题顺序,决定先写多少分的做法,遇到 bug 之后采用了什么方法调试,卡题时如何度过的难关,这些都是赛时的过程信息。

在训练阶段,如果忽视了选手拿这些分数的过程信息,会导致潜在的隐患不能被发现,比如某些题目死磕太久影响了做其他题目,或者比赛后期有多个分数可写但只能选一个写时,选的那个最后没有得分。

比如,同样是模拟赛打了 200 分,有人可能 2.5 小时就拿到了,尝试写后边的分数但未果,而有人折腾到最后才凑够。有人的分数是从前往后按顺序拿的,完全拿到一道题想拿的分数后再去做下一题,而有人是先写每道题的暴力分,再判断四道题中哪道题更好得分,从而决定后边的得分顺序。比赛后期有两个题 A 和 B 的部分分可写时,有人能力比较强,但保守策略先写简单的一个并拿到了分,但时间不够写另一个分数更高的了;有人富贵险中求,直接冲分数更高的那个,但是最后没写出来导致没有收益。

这些决策,大部分时候是有优化的空间的。多打几场比赛并对过程信息进行分析之后,每个选手都能知道自己在什么情况下适合做什么样的决策,我一般不会推荐任何一种决策,好策略是因人而异的,需要根据具体选手具体场次去具体分析。

每次模拟赛后,学生或许马上不想再做高精力消耗的事情,这个时候不妨趁着记忆比较清晰,去把自己场上的这些过程信息写下来,这个事情一般只需要花 10-20 分钟,相对比较轻松。根据我的观察,在让学生回忆完过程信息后,学生自己一般就会顺便对着这些过程信息思考,写一些经验教训,总结赛时做对以及做错了什么决策,如果学生不会分析,教练可以参与进去帮助学生复盘。这样总结过之后,即使学生真的懒得补题,但他下次的比赛策略大概率会比上一次成熟,这样就可以在不学新知识的情况下,可能拿到更多的分数。

总结

“好了,希望今天的分享对你有帮助。为了让大家能真正用起来,我为大家准备了一份 《模拟赛复盘自查清单》 的电子文档,里面列出了赛时、赛后需要关注的所有关键点。

获取方式很简单:只需要‘一键三连’本视频,并在这期视频的评论区留言‘需要复盘’,我会把下载链接私信给你。

也欢迎大家在评论区分享你打模拟赛时最难忘的一次决策失误或成功经验!”

部分分如何写以及如何对拍——以 CSP-S 2024 T2 为例

  • S 组一等,虽然新知识点无需多学了,但是有一个东西是必须要学的:对拍。并且我建议考前每道题目在提交前,都去写一个对拍去测,当成考试只有一次提交机会,交的第一次的得分就是你的成绩。假如你一道题写了不止一档分数的做法,就可以对其进行对拍,从而非常有效地检查出程序中潜在的问题。
  • 光对拍还是不够的,对拍一般来说是一个复杂度高的暴力做法和一个复杂度低的做法对拍,为了能在规定时间内跑出结果,我们不会生成很大的数据去测,必须保证暴力做法能够处理你的输入规模。但如果不测大数据,可能就测不出诸如数组开小、数值溢出、取模错误、复杂度实现错误等问题。
  • 对拍本身哪里容易写错?
  • 使用表格去记录近期自己的失误或学到的新东西。
  • 记录自己打模拟赛时的实况,用于复盘哪里可以改进。
  • 调整作息。
  • 少打乱七八糟的比赛,会影响比赛节奏,多打 OI 赛制的模拟赛。
  • 个性化精选每日一题,每天只针对性地多做一题,有效提升学习效果。

程序框架:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

// 原始输入的数据存储结构
LL n, m, L, V, p[N], d[N], v[N], a[N]; 

// 子任务 1 和 2 的做法
namespace subtask_1_to_2 {
    // 一些在本部分分中可能用到的数据结构
    bool too_fast[N]; 
    bool is_open[N];
    int max_close_cnt = 0; 
    
    // 真正的求解函数
    void solve() {
        
    }  
};

// 子任务 3 到 6 的做法
namespace subtask_3_to_6 {
    // 一些在本部分分中可能用到的数据结构
    bool too_fast[N]; 
    vector<int> open_pos;
    int max_close_cnt = 0; 
    
    // 真正的求解函数
    void solve() {
        
    }  
};

// 任务分发函数,读入数据后,判断数据具有什么特点,然后调用相应的求解函数
void dispatch() {
    cin >> n >> m >> L >> V;
    for (int i = 1; i <= n; i++) {
        cin >> d[i] >> v[i] >> a[i];
    } 
    for (int i = 1; i <= m; i++) {
        cin >> p[i]; 
    }
    
    if (n <= 20) {
     	subtask_1_to_2::solve();   
    } else if (所有的 a[i] >= 0) {
        subtask_3_to_6::solve();
    } else if (其他条件) {
        其他做法
    }
}

int main() {
    freopen("detect.in", "r", stdin);
    freopen("detect.out", "w", stdout);
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T = 1;
    // 如果不是多组数据读入,就注释掉下一行
    cin >> T;
    while (T--) {
        dispatch();
    }
    
    return 0;
} 

subtask_1_to_2 的暴力代码:

#include <bits/stdc++.h>

#define x first
#define y second

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10;

LL n, m, L, V, p[N], d[N], v[N], a[N]; 

namespace subtask_1_to_2 {
    bool too_fast[N]; 
    bool is_open[N];
    int max_close_cnt = 0; 
    
    void dfs(int u) {
        if (u == m + 1) {
            for (int i = 1; i <= n; i++) {
                if (too_fast[i]) {
                    bool found = false;
                    for (int j = 1; j <= m; j++) {
                        if (p[j] >= d[i] && is_open[j]) {
                            LL v2 = v[i] * v[i] + 2 * a[i] * (p[j] - d[i]);
                            if (v2 < 0) {
                                break;
                            }
                            if (v2 > V * V) {
                                found = true;
                                break;
                            }
                        }
                    }
                    if (!found) {
                        return;
                    }
                }
            }
            
            int cnt = 0;
            for (int i = 1; i <= m; i++) {
                if (!is_open[i]) {
                    cnt++;
                }
            } 
            
            max_close_cnt = max(max_close_cnt, cnt);
            
            return;
        } 
        
        dfs(u + 1);
        is_open[u] = false;
        dfs(u + 1);
        is_open[u] = true;
    } 
    
    void solve() {
        for (int i = 1; i <= n; i++) {
            too_fast[i] = false;
        }
        
        for (int i = 1; i <= n; i++) {
            bool ok = true;
            for (int j = 1; j <= m; j++) {
                if (p[j] >= d[i]) {
                    LL v2 = v[i] * v[i] + 2 * a[i] * (p[j] - d[i]);
                    if (v2 < 0) {
                        break;
                    } 
                    if (v2 > V * V) {
                        ok = false;
                        break; 
                    }
                }
            }
            if (!ok) {
                too_fast[i] = true;
            }
        } 
        
        int too_fast_cnt = 0;
        for (int i = 1; i <= n; i++) {
            if (too_fast[i]) {
                too_fast_cnt++;
            }
        }
        cout << too_fast_cnt << " ";
        
        max_close_cnt = 0;
        for (int i = 1; i <= m; i++) {
            is_open[i] = true;
        }
        dfs(1); 
        
        cout << max_close_cnt << "\n";
    }  
};

void solve() {
    cin >> n >> m >> L >> V;
    for (int i = 1; i <= n; i++) {
        cin >> d[i] >> v[i] >> a[i];
    } 
    for (int i = 1; i <= m; i++) {
        cin >> p[i]; 
    }
    
    subtask_1_to_2::solve();
}

int main() {
    #ifdef LOCAL_FILE_IO
    freopen("detect.in", "r", stdin);
    freopen("detect.out", "w", stdout);
    #endif
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    
    return 0;
} 

性质 A 和 B 的代码:

#include <bits/stdc++.h>

#define x first
#define y second

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 2e5 + 10;

LL n, m, L, V, p[N], d[N], v[N], a[N]; 

namespace subtask_3_to_6 {
    void solve() {
        int too_fast_cnt = 0;
        for (int i = 1; i <= n; i++) {
            if (p[m] < d[i]) {
                continue;
            } 
            LL v2 = v[i] * v[i] + 2 * a[i] * (p[m] - d[i]);
            if (v2 > V * V) {
                too_fast_cnt++;
            }
        }
        
        cout << too_fast_cnt << " ";
        if (too_fast_cnt == 0) {
            cout << m << "\n"; 
        } else {
            cout << m - 1 << "\n";
        }
    }
};

void solve() {
    cin >> n >> m >> L >> V;
    for (int i = 1; i <= n; i++) {
        cin >> d[i] >> v[i] >> a[i];
    } 
    for (int i = 1; i <= m; i++) {
        cin >> p[i]; 
    }
    
    subtask_3_to_6::solve();
}

int main() {
    #ifdef LOCAL_FILE_IO
    freopen("detect.in", "r", stdin);
    freopen("detect.out", "w", stdout);
    #endif
    
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    
    return 0;
} 

数据生成代码:

#include <bits/stdc++.h>

using namespace std;

int rd(int a, int b) {
    return rand() % (b - a + 1) + a;
}

int main() {
    srand(time(NULL));
    int T = rd(1, 3);
    cout << T << "\n";
    while (T--) {
        int n = rd(5, 10), m = rd(5, 10);
        int L = rd(1, 1000000), V = rd(1, 1000);
        cout << n << " " << m << " " << L << " " << V << "\n";  
        for (int i = 1; i <= n; i++) {
            int d = rd(1, L), v = rd(1, 1000), a = rd(0, 1000);
            if (rand() % 2) {
                a *= -1;
            }
            cout << d << " " << v << " " << a << "\n";  
        } 
        vector<int> p; 
        for (int i = 1; i <= m; i++) {
            p.push_back(rd(0, L)); 
        }
        sort(p.begin(), p.end());
        for (auto pos : p) {
            cout << pos << " ";
        }
        cout << "\n";
    } 
    return 0;
}

对拍检查代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    system("g++ detect.cpp -o wrong.exe -Wall -std=c++14 -O2 -static");
    system("g++ d.cpp -o correct.exe -Wall -std=c++14 -O2 -static");
    system("g++ gen.cpp -o gen.exe -Wall -std=c++14 -O2");
    while (true) {
        system("gen.exe > in.txt");
        system("wrong.exe < in.txt > wrong.out");
        system("correct.exe < in.txt > correct.out");
        if (system("fc wrong.out correct.out")) {
            system("pause");
            break;
        } 
    } 
    return 0;
}

小红书文案

标题:CSP-S最后20天冲省一?教练说破大实话!(弱/中等省必看)

正文

CSP-J/S 第二轮将于 11 月 1 号开考,时间紧,任务重!最后20天,方向比努力更重要

如果你在一等奖分数线120-170分的省份,且目标就是 “稳稳上岸” ,这篇笔记就是为你写的。作为前竞赛选手以及现在的竞赛教练,不讲空话,全部都是硬核分析与建议!

👇🏻下方长图,是我为冲刺学员总结的最后 20 天冲刺攻略,包含:

  1. 💡 分数拆解真相:CSP-S每道题的分数是怎么构成的?告诉你哪些分是必须拿到手的,哪些分可以战略性放弃
  2. 🎯 能力精准定位:想压线省一,到底需要具备什么水平?你需要专注练习哪种难度哪种知识点的题目?(答案可能比你想象的简单!)
  3. 🛠️ 学员实战案例:展示真实学员的复盘表格模拟赛实况记录,看他们如何通过“精细化复盘”实现提分。
  4. ❗ 核心避坑指南:为什么赛前不要乱打CF?为什么不能死磕难题?考前最影响心态的几件事,帮你一一避坑。

本文价值:帮你把有限的备考时间,最大化地转化为考场分数。拒绝无效努力,冲刺省一,看这一篇就够了!

➡️ 赶紧收藏点赞,把图片存好,对照执行吧!

赞赏