PTA在线判题作息表:测试点推进、止损线与复盘节奏
PTA 这类在线判题平台最不缺的就是题缺的是节奏。很多人打开题目集的第一反应是往下翻翻十分钟挑一道看着顺眼的写二十分钟卡住退出来换个题目集接着翻一天下来提交记录里躺着三四条“部分正确”。我带过几批做上机训练的人之后最大的感受是刷题这件事的分水岭既不在智商也不在刷了多少道而在于有没有一张把时间钉死的作息表。“PTA 老板的作息表”这个说法原本指的是带队的那位负责人在群里发的一张日程——几点到几点干什么、每段产出什么、什么情况下必须停手。它解决的不是“题不会做”的问题是“一天过去了不知道自己干了什么”的问题。下面我把这张表的骨架、每一段的设计理由、以及我照着跑下来踩过的坑完整拆一遍。刚接触在线判题的新手可以照着抄时间框架已经刷了一段时间但卡在瓶颈的人重点看第二、三部分的配比逻辑和第五部分的排查路径。1. 这张作息表为什么长这个样子1.1 先认清判题机制才谈得上排时间排作息表之前必须先搞清楚你面对的是一个什么样的反馈系统因为它决定了你每一段时间该换来什么。PTA 的判题是“测试点制”一道题背后藏着若干组数据每组独立跑跑过给分、跑挂不给分最后汇总成一个结果码。这意味着你看到的不是“对/错”两个状态而是一条连续的分数曲线——60 分、80 分、95 分都是常态。这个特性直接决定了时间安排你不能用“做完一道题”作为时间单位只能用“推进一个测试点”作为时间单位。我在排表的时候把这件事想得很透。一道 25 分的综合题从 0 分推到 20 分可能要一个小时从 20 分推到 25 分可能要再一个小时而最后那 5 分往往是边界数据、特殊输入、精度处理。如果不提前划分人很容易陷在最后 5 分里出不来一整天的计划全废。所以作息表里每段任务都必须写明“这段的验收标准是什么”而不是“这段做几道题”。还有一点容易被忽略PTA 的时间限制通常压得很紧多数题在几百毫秒到一秒之间。这不是为了刁难人而是逼你在写代码的时候就考虑复杂度。排表的时候我把“复杂度估算”单独抽出来做了一段固定动作原因就在这里——判题机不会告诉你哪里慢它只告诉你超时你得自己在动手前就把量级算清楚。n 给到 10 万你写个双层循环就是 100 亿次操作必然超时这个判断应该在读题阶段完成而不是提交之后对着“运行超时”发呆。1.2 三个硬约束决定了时间怎么切作息表不是拍脑袋排的它背后有三个绕不开的约束我把它们摆在一起看时间切分自然就出来了。第一个约束是注意力时长。高强度推导类任务绝大多数人撐不过 90 分钟就开始出现“读了三遍还没读懂题”的状态。所以表里所有攻坚段都卡在 75 到 90 分钟到点必须换类型哪怕题没做完。这一条我一开始不服觉得自己能连着写三小时实测两周后发现第三个小时写出来的代码返工率是前两个小时的将近三倍纯属负收益。第二个约束是反馈周期。在线判题的反馈是秒级的这既是好事也是陷阱。好事是你能快速验证想法陷阱是你会不自觉地“边写边交”把一道题拆成十几次提交每次改动一点点靠判题机替你调试。这种做法短期爽长期毁手感。表里因此规定单题提交次数原则上不超过三次第三次还不过就转入手动构造测试数据的环节。第三个约束是遗忘曲线。昨天想明白的解法今天大概率只剩下一个模糊印象。所以表里每天固定安排一段“复现”时间不看题解、不看昨天代码纯手写。这一段是最痛苦的也是收益最高的。我把这段放在下午因为上午攻坚之后脑子已经疲了做新题的边际效率很低但做复现刚好——它需要的是记忆提取而不是创造。1.3 为什么别人排的表比自己排的管用自己排的计划有个致命问题它是可协商的。今天状态不好那段就算了这道题有意思多写半小时。一天两天无所谓一个月下来计划表就变成了一张愿望清单。带队的负责人排的表之所以管用核心不在于他更懂算法而在于他把判断权从执行者手里拿走了。几点切换、什么时候必须停、什么情况下允许看题解这些全部前置规定好执行的时候不需要再做决策。决策是要消耗意志力的而意志力在连续解题的过程中消耗极快等你把意志力花在“要不要再试十分钟”这种问题上真正用来想算法的就不够了。我在自己的表里加了两个硬规则效果比任何技巧都明显。第一条是止损线单题超过 45 分钟没有实质进展连续两次提交分数不变或者思路卡在同一个地方超过 15 分钟立刻停止去看题解的思路部分但不看代码看完合上自己重写。第二条是离屏时间每 90 分钟强制离开屏幕 10 分钟不刷手机就是走动、喝水、看远处。这两条听着像养生实际是为了保证后半天还有脑子可用。2. 一天的节奏拆解每段时间到底在干什么2.1 早段低强度输入先把脑子热起来早上的第一段不安排攻坚安排的是“输入型任务”大概 40 到 50 分钟。具体内容是把昨天标记过的题目重新读一遍题干和输入输出格式不动手写只在纸上写两样东西这道题的数据范围是多少、我打算用什么复杂度。这一步看着简单实际能筛掉一大半的低级错误。我踩过的坑就在这里。刚上手那阵子读题基本靠扫看到“给定一个整数 n”就直接往下写结果数据范围那一行写着 n 不超过 10 的 5 次方元素值不超过 10 的 9 次方两数相加直接爆 int。这类错误在 PTA 上会表现为“部分正确”测试点里总有几个大数过不去而你盯着代码看半天看不出问题因为代码逻辑确实没错。早段还要做一件事把当天要用的代码模板过一遍。模板不是让你复制粘贴是让你在动手前确认输入输出、数据类型、循环边界这些骨架部分没记错。我用的是一个固定的骨架每次开工前默写一遍两三分钟的事能省掉后面半小时的调试。2.2 上午段高强度攻坚一次只啃一个点上午是全天效率最高的窗口安排两段 75 分钟的攻坚中间隔 15 分钟。这两段只做一件事做那些需要真正想清楚的题比如图论里的最短路变形、动态规划的状态设计、复杂模拟题的边界梳理。这里有个反直觉的经验攻坚段不要按“简单到难”排序要按“能不能在 75 分钟内看到进展”排序。有些难题你知道自己想不出硬啃只是浪费时间有些中等题你一上手就知道有戏那就先做它把状态拉起来。我一般的排序是一道有把握的 一道没把握的交替着来。攻坚段里有个具体操作很值得说在纸上写状态定义再写代码。动态规划尤其如此。状态转移方程写不出来多半是状态定义错了而不是你不够聪明。我在纸上会写三行状态是什么、转移从哪来、边界是什么。这三行写不清楚就不打开编辑器。这个习惯养成之后我对“运行超时”和“答案错误”的恐惧少了一大半因为大部分错误在纸上就被拦住了。2.3 下午段手写复现把别人的解法变成自己的下午安排 90 分钟的复现段这是整张表里我最不想执行、但收益最大的一段。具体做法是挑昨天或今早看过题解的一道题合上所有参考资料从空白文件开始重写一遍。写不出来的地方做标记写完之后对照题解找差距。这一步的价值在于“提取练习”。看题解的时候大脑产生的是“识别感”——哦原来是这样我懂了。但识别和提取完全是两回事。看懂别人的代码和自己从零写出等价逻辑中间隔着的正是真正的能力。我做过一个粗略统计第一遍看题解觉得“完全理解”的题合上重写能够一次通过的不到四成剩下六成里有一半会卡在初始化、边界、下标偏移这些细节上。复现段还有个变体适合时间紧的情况只写核心函数。完整代码太长的话就只写那个关键的函数体比如二分查找的边界判定、并查集的合并与路径压缩、拓扑排序的入度更新。这部分写对了外围的输入输出都是体力活。2.4 晚间段复盘归档把经验变成可检索的条目晚上安排 60 分钟复盘不写新代码。复盘要产出一个东西一条可以被未来的自己检索到的记录。格式固定三行——这道题考的是什么、我卡在哪一步、下次遇到同类题的第一反应应该是什么。举个具体的例子。有一类题要在无向图里判断连通分量个数用并查集做卡了我很久的点不是并查集本身而是“怎么处理孤立点”。记录写下来就是考并查集计数卡在孤立点的初始化下次先数点初始化为 n每成功合并减一。这条记录五十个字下次再遇到同类题三十秒就能想起来。复盘还要做一件容易被跳过的事清理提交记录里的错误分类。把当天所有非“答案正确”的提交拉出来按错误类型归一下类。如果一天里“格式错误”出现了三次以上说明你输出格式控制有大问题第二天的早段就应该专门练这个而不是继续刷新题。很多人复盘只看“这题会不会”不看“我为什么错”结果是同一个坑一周能踩五遍。3. 题目分层与每周配比别把时间花在无效刷题上3.1 四层分类法每一层的目标完全不同把题目按“你从这道题里获得什么”分成四层比按难度分有用得多。层级特征单题目标耗时主要收益基础层语法、输入输出、简单分支循环10 到 15 分钟手感与准确率模板层排序、二分、并查集、最短路等固定套路20 到 30 分钟代码熟练度综合层多个知识点串联需要设计结构45 到 75 分钟拆解与建模能力边界层专门考精度、大数、特殊输入30 到 60 分钟严谨性这个分层的价值在于它让你知道每一层该用什么心态去对待。基础层追求的是零失误不是做出来就行而是每一次提交都必须是“答案正确”一次都不许有格式错误。模板层追求的是默写速度目标是合上书本能把并查集写完且一次通过。综合层追求的是思路成立分数不到位可以接受思路错了才是真问题。边界层追求的是覆盖完整把能想到的特殊情况列成清单逐条验。我见过不少人卡在瓶颈问题就出在层级错配天天泡在综合层里基础层的格式错误率却居高不下导致综合题的分数永远卡在七八十上不去。这就像盖房子地基没夯实就往上层堆材料。3.2 每周配比与难度爬坡一周的时间按 6 天排留一天机动。工作日每天 4 到 5 小时有效训练周末两天各 6 小时左右其中一天做整卷模拟。层级每周题量占比时间占比安排位置基础层30%15%早段模板层30%25%上午前段综合层30%45%上午后段 下午边界层10%15%下午后段注意题量占比和时间占比是反过来的。基础层题多但简单占三成题量只用一成半时间综合层题量也是三成却要吃掉将近一半时间。这个错配是故意的因为你真正需要成长的地方就是综合层基础层只是维持手感。难度爬坡有个简单的判断标准当前难度下你的首提交通过率保持在 50% 到 70% 之间就是合适的档位。低于 50%说明题太难做着做着就变成看题解学习效率极低高于 70%说明题太简单你只是在重复已经掌握的东西没有新刺激。这个比例我调整过好几次稳定在这个区间之后进步速度明显比之前“随便挑题”快得多。3.3 单题止损线和时间预算的具体算法止损线不要拍脑袋定用这个公式算止损时间 该题目标耗时 × 1.5。目标耗时参考上一节的表格。综合层的题目标 60 分钟止损线就是 90 分钟模板层的题目标 25 分钟止损线就是 37 分钟左右超过就停。为什么是 1.5 倍而不是 2 倍因为超过 1.5 倍之后你能获得的边际收益急剧下降。剩下的时间里你多半是在做两件事反复改同一处代码或者干脆发呆。这两件事都不产生学习。止损之后做什么也要提前规定好否则你会陷入“停下了但不知道干嘛”的状态。我的做法是分三种情况一是思路完全没有去看题解的思路部分看完合上自己写二是思路有但实现不出来去翻自己的模板库或者笔记找同类题的实现三是思路和实现都有但过不了测试点转去手动构造边界数据用打印中间变量的方式定位。这三种情况的处理方式完全不同混着来就是浪费时间。4. 一次完整训练日的实操记录4.1 开工前的环境与模板准备开工前五分钟做三件事打开编辑器、确认语言和编译选项、默写一遍主函数骨架。PTA 上不同题目支持的编译器版本可能不一样有的题允许较新的标准有的只到较老的版本提交前扫一眼题目页面的说明能省掉一次莫名其妙的编译错误。我的主函数骨架长这样基本不用改#include bits/stdc.h using namespace std; const int MAXN 100005; int a[MAXN]; // 大数组一律放全局避免爆栈 int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; while (scanf(%d, n) ! EOF) { // 多组输入的标准写法 // 处理逻辑 } return 0; // 千万别漏漏了就是返回非零 }这里有两个细节值得展开。第一ios::sync_with_stdio(false)这一行是给 C 流加速用的很多题的时间限制很紧不加这一行用cin读十万级数据可能直接超时。第二多组输入的写法PTA 上不少题是“输入多组数据直到文件结束”如果你只读一组就退出结果会是“答案错误”或者只过一部分测试点。大数组放到全局这件事我要多说一句。局部变量分配在栈上栈空间通常在几 MB 量级你写个int arr[1000005]放局部四兆字节直接栈溢出判题机报给你的是“段错误”而不是“内存超限”。这个错我当年找了整整一个下午最后才发现是把数组挪到全局就好了。4.2 输入输出的细节占低级错误的一大半输入输出看着最简单实际上是最容易掉分的地方。列几个高频问题。关于混合使用cin和scanf如果关了同步两者混用会出问题读入顺序错乱。要么全用 C 风格要么全用 C 风格别混。关于getline和cin cin 读完一个数之后换行符会留在缓冲区里紧接着调getline会读到一个空串。解决办法是在中间加一次cin.ignore()或者干脆全部用getline读进来再自己解析。关于输出格式行末不能有多余空格这是一条铁律。很多题的输出是“数字之间用一个空格分隔”你最后多打一个空格判题机比对字符串就直接判“格式错误”但分数往往给一部分让人以为是算法问题。我的做法是统一写成“第一个元素单独输出后面每个元素输出前加空格”这种模式从结构上杜绝末尾空格。关于浮点数不要用比较两个浮点数用fabs(a - b) 1e-8。输出要求保留两位小数时注意printf(%.2f)的行为以及某些题目对“四舍五入”和“四舍六入五成双”的要求差异。涉及金额、比例的输出先把样例手算一遍对上了再提交。4.3 提交、调试、定位的固定流程我把提交后的动作做成了一套固定流程避免瞎改。第一次提交不过先看结果码不要看代码。结果码是“格式错误”问题几乎必然在输出格式去检查末尾空格、空行、大小写结果码是“运行超时”问题在复杂度或者死循环结果码是“段错误”问题在数组越界或者递归过深结果码是“答案错误”且分数很低问题在算法思路分数很高只差一两个测试点问题在边界处理。定位“答案错误”的时候最有效的办法是自己构造小数据。题目给的样例通常太简单你得造那种“刚好能触发边界”的数据n 等于 1、n 等于最大值、所有元素相同、元素有负数、图不连通、只有一个点没有边。这些小数据用打印中间变量的方式跑一遍问题基本都能现形。还有一个技巧把printf调试法和分治排查法结合起来。先在代码里几个关键节点打标记确认程序走到了哪一步如果确认流程正确但结果不对就把输入规模缩到最小比如 n2手工推演一遍看程序输出和自己的推演差在哪。这个办法笨但是万能。4.4 复盘表怎么写才有用复盘表不是流水账要能被将来的自己检索到。我的表有四列题目特征考查点卡点下次的第一反应无向图连通块计数并查集孤立点没算进去先初始化为 n每合并一次减一区间查询最值线段树 / 稀疏表边界包含关系写反先确定左闭右闭还是左闭右开字符串模式匹配KMP 的 next 数组next 数组下标从 0 还是 1 开始先看题解用的是哪种约定第三列“卡点”是最值钱的一列。它记录的不是“我不会”而是“我具体在哪一步错了”。一个月后翻回来你会发现自己的卡点高度重复——可能八成的问题都集中在三种类型上初始化、边界、下标偏移。发现这个规律之后你可以在写代码时有意识地在这三处多检查一遍效率提升非常直接。5. 常见问题与排查技巧实录5.1 判题结果速查表下面这张表是我自己总结的贴在显示器旁边出问题先扫一眼。结果码最可能的原因第一步该看哪里答案正确通过记录思路归档格式错误行末空格、空行、大小写、缺换行输出语句答案错误低分算法方向错重新读题看数据范围答案错误高分边界、特殊输入构造 n1、极值、重复元素运行超时复杂度过高、死循环、输入太慢算一遍量级检查循环条件段错误数组越界、递归过深、局部大数组数组声明位置、递归深度浮点错误除零、对负数开方、取模零分母是否可能为零返回非零主函数没写 return 0主函数末尾编译错误语言版本、头文件、拼写提交时的语言选项这张表的价值在于缩短“发现问题”的时间。真正耗时的从来不是改代码而是不知道自己错在哪反复提交试探。5.2 运行超时的三条排查路径运行超时是最容易让人误判的问题因为代码看起来完全正确。按这三条路径走。路径一算复杂度。把数据范围拿出来n 多大、边多少、查询多少次乘一下操作总数。经验值是每秒能跑一亿次左右的简单操作超过这个量级就得换算法。n 是十万、你要做双层循环那就是一百亿次铁定超时这时候再怎么优化常数都没用必须换思路。路径二查死循环。循环变量有没有在循环体内被正确更新边界条件是还是while里的条件会不会永远为真。这类错误有个特征小数据能过大数据超时因为小数据循环几次就结束了大数据会一直转。看到“小数据通过、大数据超时”先怀疑死循环。路径三查输入输出开销。这一条最隐蔽。算法复杂度是对的但输入用了没加速的cin或者输出用了endl频繁刷缓冲几十万次下来就是几百毫秒。改用scanf/printf或者关同步、把endl换成\n往往能直接过。5.3 段错误和浮点错误的现场处理段错误的排查有个套路先看数组再看递归最后看指针。数组方面检查声明的大小够不够、下标有没有到 n 而不是 n-1、有没有负数下标递归方面检查终止条件是否可达、递归层数会不会达到几十万层指针方面检查有没有使用未初始化的指针。有个特别隐蔽的情况声明了int a[1000]题目数据是 1000 个元素你从 0 填到 999 没问题但某处循环写成了i n访问到a[1000]越界一个元素。这种越界在有些环境下不会立刻崩溃只是悄悄改掉下一个变量的值表现出来是“答案莫名其妙不对”查起来极其痛苦。所以数组一律开大一点多开十个元素几乎不花成本。浮点错误相对少见但一旦出现很有规律找分母。除法的分母、取模的右操作数、开方的参数、对数的真数逐个检查是否可能为零或负数。还有一种情况是类型转换整数除法被截断导致后续计算全错这种不会报错只是结果不对需要在小数据上手动验算。5.4 节奏崩了怎么救再怎么排表也会遇到一整天状态稀烂的时候题读不进去代码写一行改三行提交一次错一次。这时候最忌讳的是“硬撑”撑到晚上只会得到一堆挫败感。我的处理办法是把当天的任务降级不是取消。攻坚段改成模板层练习做几道熟练的题找找手感复现段改成读题解不动手写复盘段照常做。这样一天下来虽然没进步但也没有断掉节奏第二天恢复起来很快。反过来如果连续三四天都是这个状态那问题不在状态在安排。要么是难度档位调得太高要么是训练时间排得太满没有恢复空间。这时候应该往回退一档把首提交通过率拉回 50% 以上稳定一周再往上走。我自己的经验是爬坡爬得太急退回来重爬花的时间比稳扎稳打还多。最后说一个我个人一直在用的判断标准如果一天训练结束你能用三句话说清楚今天解决了什么问题、卡在了哪里、明天第一件事做什么那这一天就是有效的不管做了几道题。说不清楚做二十道也是白做。