“0x3f第29天复习”这串字符如果你不懂算法竞赛圈的梗猛一看会以为是什么暗号。其实0x3f是十六进制数63在代码世界里它几乎快成了“无穷大”的代名词——0x3f3f3f3f是无数OI和ACM选手初始化距离、DP数组时最顺手的值。而我一个坚持算法打卡第29天的普通学习者今天想认真聊聊这次“8.34-9.41”的复习记录背后到底复盘了什么以及为什么第29天才是真正容易翻车、也真正能拉开差距的节点。这篇内容适合正在按计划刷题、准备面试算法、或者单纯想建立长期学习节奏的人我会把复习思路、时间分配和踩过的坑一次性讲透。1. “0x3f”与我的算法学习第29天——先把这个标题拆开看1.1 0x3f到底是什么先解决一个可能困惑新手的问题为什么大家都爱用0x3f3f3f3f而不是写INT_MAX早年间我在Windows上写CINT_MAX是2147483647看着很安全但有两个隐患第一如果用INT_MAX去初始化距离数组一旦代码里出现dist[u] w很可能直接整数溢出变成负数整个最短路逻辑直接崩掉第二INT_MAX参与加法会产生未定义行为靠编译器心情做事。而0x3f3f3f3f等于1061109567大约是10^9级别比一般数据范围上限大得多两个0x3f3f3f3f相加是2122219134仍然小于INT_MAX不会溢出。memset按字节填充时0x3f3f3f3f每个字节都是0x3f一条memset(dist, 0x3f, sizeof dist)就能把整个数组干净地初始化为同一个“大数”这就是这个魔术常量的核心优势。所以“0x3f”不只是个数字它代表了一种减少心智负担的编码习惯也代表算法竞赛圈里那些“约定俗成的智慧”。用这个词作为复习日志的编号对我来说还有另一层意思它提醒我很多看似玄乎的技巧拆开看底层逻辑都特别朴素就像0x3f的选用本质就是“大数不溢出方便memset”三条原则。1.2 为什么是第29天——复习节奏的临界点21天养成习惯的说法深入人心但真实的算法学习里第21天往往还处在“对模板半生不熟”的阶段。到了第29天你大概率已经过了最初的新鲜感开始面对最现实的问题前面学的开始忘了。我自己的学习计划是每天投入一到两小时前两周主攻基础数据结构和贪心中间一周切入图论和搜索最近一周开始碰动态规划。但在第26天左右我回头做第一周做过的题目居然发现邻接表的写法都要想半天。那一刻我意识到不能再无脑往前刷了必须系统复习。第29天就是这个复习周期的第一棒——笔记上写着的8.34-9.41正是我不看手机、不刷视频、完整留出来的67分钟复盘时间。为什么偏偏是67分钟因为这个时长刚好能装下“三个主题复习一道重做题笔记补漏”再长会明显疲劳再短则连状态都还没热起来。第29天的意义本质上就是在习惯真正固化之前主动刹车一次把松动的根基重新砸实。1.3 8.34-9.4167分钟的黄金复盘时段8.34开始不是巧合。早上大脑前额叶功能最清醒适合做需要高度专注的“回忆型复习”而不是被动地看笔记。我试过晚上复习结果往往是从“看一遍模板”变成“刷手机十分钟”因为晚上的自我约束力已经消耗得差不多了。这67分钟我的策略是前20分钟闭卷回忆中间30分钟重做经典题最后17分钟对照总结。为什么把重做题放在中间而不是开头因为如果一上来就做题大脑会直接进入“搜索解法”模式这会跳过“提取记忆”的过程。记忆的核心不是多看而是成功提取。先合上书回忆一遍今天要复习的算法框架再做题提取效率完全不同。2. 复习到底复盘什么——第29天的核心内容拆解2.1 数据结构模块把“0x3f”这类无穷大用活第29天我给自己定的复习范围是前半个月的内容数据结构这里重点关注线段树和并查集。说实话线段树这种东西写的时候觉得自己会了三天不碰再看代码就像看天书。复习线段树关键是在一张白纸上从零推导四个函数build、pushup、update、query。有个细节特别值得拿出来说——pushup是线段树的灵魂。很多新手写线段树喜欢把维护逻辑塞进update里结果一旦涉及区间覆盖、区间加的复合操作代码立刻失控。正确的抽象方式是让所有子节点更新完之后通过pushup统一汇总父节点信息。这样无论是单点修改还是区间修改父节点更新逻辑只有一处调试时只需要盯着这一个函数。我用一个自己踩过的坑总结一下线段树区间加懒标记时node[p].tag k和node[p].max k的顺序不能反。先更新存储值再更新懒标记这两步看似无所谓但如果你先更新tag再更新max而max的更新公式里恰好用到孩子节点、系统会按旧tag执行后续pushdown就出错了。这种顺序细节只有重新静下心写一遍才能发现。2.2 图论与搜索从模板到变形题第三周图论部分我复习了Dijkstra最短路、并查集判环、拓扑排序和DFS回溯。图论是很容易“背模板”的领域你上周能把Dijkstra的优先队列写法默写出来不代表今天还能。我的复习方法是不看模板只凭记忆写出堆优化Dijkstra然后拿去跑一道当初做过的裸题。如果你也正好在图论复习阶段我会特别提醒一个被轻视的细节优先队列排序要用pair第一维距离、第二维节点编号。因为priority_queue默认是大根堆pair排序先比第一维再比第二维刚好符合“先取出距离最小”的需求。如果只存节点编号却想自定义比较淘汰器写起来容易绕晕。另外求最短路径条数时dist相等也要执行cnt[v] (cnt[v] cnt[u]) % MOD而不是只在找到更短路时更新这是很多变形题的埋雷点。搜索部分DFS回溯我总是强调“撤销操作”和“剪枝”的关系。很多人把剪枝当成一种优化手段其实在超大数据范围下没有剪枝的DFS就是暴力枚举时间复杂度是灾难级的。复习时我建议把决策树的形态画出来标注哪些分支可以被可行性剪枝、哪些需要最优性剪枝这个功夫能帮你节省大量实战时间。2.3 动态规划常见状态设计的复盘动态规划是第29天复习的重头戏。DP的难点从来不是转移方程本身而是为什么状态要这么定义以及初始化边界为什么要是这个值。比如背包问题为什么dp[0] 0、其他位置初始化为负无穷因为“恰好装满”和“不超过容量”两种问法的初始化策略完全不同——前者要求必须从容量0开始拼凑后者天然允许任何容量下都继承0。复习时我会挑三个经典模型各写一遍0-1背包、最长上升子序列、区间DP。区间DP里最经典的合并石子/矩阵链乘问题它的三层循环结构值得反复默写先枚举区间长度再枚举左端点最后枚举分割点。如果我发现自己连“为什么先枚举长度而不是先枚举左端点”都要想半天那说明上一轮学得其实不透彻复习的价值就在这里体现——逼你诚实地面对知识漏洞。3. 实操过程一个67分钟复习时段怎么安排3.1 时间分配表我把8.34到9.41这67分钟拆成了五段每段都有明确的输出物。没有输出的复习都是自我安慰。时间段时长复习动作预期输出8.34-8.4511分钟合上笔记在空白纸上列出本周学过的全部算法名称一张“算法地图”检验能回忆多少8.45-8.5510分钟凭记忆实现线段树区间最大值的四个核心函数能跑通的代码片段8.55-9.1015分钟重做一道最短路径计数题裸题AC或明确知道自己卡在哪一步9.10-9.3020分钟闭卷补写0-1背包、LIS、区间DP的模板三份手写模板9.30-9.4111分钟对照原笔记划出遗忘点写下三条改进提示三条可执行的明日要点这张表最核心的设计思路是“先回忆、后对照”。如果你一开始就翻开笔记看模板那你永远不知道自己到底忘了多少。复习最忌讳的就是把“看到认识”当成“会了”闭卷输出才能照出原型。3.2 具体操作步骤与细节第一步的“算法地图”并不是把所有算法名写出来就完了而是要给每个算法标星号——三颗星表示“闭卷能写”两颗表示“需要提示”一颗表示“完全没印象”。经过三周学习我最后标出的两星和三星大概各占一半没有一颗星的但这个结果比我想象中乐观说明前期刷题确实在起作用。第二步线段树是个硬骨头。我先在纸上画出一棵区间[1,8]的线段树然后从build函数开始写。写update的时候手会自然停下来因为要回忆lazy标记到底在什么时机下放。我的经验是能不用懒标记就尽量不要用。很多看似需要区间更新的题其实可以用差分思想或者树状数组绕开这样代码短调试更简单。但一旦真需要区间更新区间查询懒标记必须掌握我的记忆锚点是一句话“pushdown先传给两个孩子再做区间操作”。第三步重做最短路计数题。这题当初第一次做的时候我卡了将近一个小时现在做应该流畅很多。实际动手之后我发现自己还是在边界处理上犹豫了一下——cnt[s]要不要初始化为1答案是要因为起点到自己的路径就是一条路径。这类细节重做旧题比刷新题更容易暴露。第四步是DP模板的三件套默写。0-1背包注意一维逆序LIS注意维护的是“最小末尾值数组”区间DP注意枚举长度的循环顺序。这三个模板写下来我估算至少要十五分钟所以时间表里给它排了20分钟留一点缓冲。第五步是收尾。我对照原笔记把遗忘点分成两类一类是“概念懂了但代码忘了”的比如线段树的pushdown写法另一类是“当初就没理解透”的比如区间DP为什么枚举长度要放外层。前者明天重写一遍就能解决后者需要找一道新题再验证。这十一条改进提示是我今天复习真正的产出物。3.3 我的记录方法别在复习时“自我感动”有一个很要命的问题就是复习着复习着变成了重新学习。你原计划只是过一遍线段树结果看到某个细节不明白直接打开题解刷了三道新题。等回过神来67分钟结束了当初计划中要复习的DP模板一个没写。我的解决办法是在手机备忘录里建一个“复习日志”的表格每一行只有三个字段复习主题、是否闭卷完成、发现的问题。严格规定复习过程中不打开新题。每当脑子里冒出“不如顺便做一道新题巩固一下”的念头我都会强迫自己先记在“发现的问题”里这相当于给冲动一个“等一下再说”的缓冲。实际体会是大部分冲动过十分钟就消失了而那些真值得去查漏的知识点在第二天的固定学习时间段里处理效果远好于复习中途临时加塞。4. 常见问题与避坑指南4.1 忘得比学得快怎么办这是第29天遇到的最大情绪冲击。明明上周还能熟练写出来的Dijkstra为什么今天默写就漏了优先队列的greater比较器后来我想明白了这不是你“不行”而是人类的记忆曲线就是这样的。遗忘是正常现象不是能力缺陷。你的目标不是让记忆永不消逝而是在它消逝前建立足够的提取路径。我的方法有两个第一每个算法至少建立两条“提取线索”比如Dijkstra不仅记“每次找最小距离点”还记“看起来像BFS贪心本质是优先队列反复出队”第二把模板拆成“为什么”和“怎么写”两层来记很多代码细节只要理解了逻辑就忘不掉比如堆优化Dijkstra的核心本质就是用小根堆替代O(n^2)扫描找最小值想到这个层面代码自然就还原出来了。4.2 从“看得懂”到“写得出来”之间的鸿沟怎么填很多人学算法时有这种体验看题解一看就懂合上题解一写就废。我在第29天重做旧题时也遇到了这个现象——题目很眼熟官方解法烂熟于心但手放键盘上第一行代码就犹豫了因为没想清楚到底要从输入建图开始还是先定义邻接表。这个问题的根源在于“理解”和“执行”用的是大脑的不同区域。解决方法只有一条刻意练习“从零写完整代码”而不是“补全代码”。复习时不要打开已经写好的模板去填空而要把模板收起来真的从#include开始写。哪怕写得又慢又丑这个过程能把那些只停留在视觉层面的知识转变成肌肉记忆层面的能力。我给自己定了一个硬指标每个算法模板至少独立默写三次间隔分别是一天后、三天后、一周后。第一次默写会非常痛苦第二次会好很多第三次基本能一分钟内写对核心结构。第29天这次复习相当于第二轮默写的一部分。4.3 时间不够用怎么办——给复习做减法如果你是上班族或者课业繁重每天未必能抽出一整个小时复习。我的建议是把复习内容压缩到“一个最小集”只复习当天必须巩固的一个知识点一道重做旧题总时长控制在25分钟以内。这也是为什么我特意把每次复习主题“单元化”每次只安排两三个主题而不是试图在一天内翻完整本笔记。具体的减法优先级是第一优先重做做错的经典题第二优先闭卷默写一个模板第三优先浏览概念性笔记。做错题之所以放最高优先级因为错题代表你真实的薄弱点而概念性笔记浏览往往只是在增加“熟悉感”的错觉。第29天这67分钟里我做的最有价值的一件事就是重新手写了一遍当初错了好几轮的线段树区间更新而且这次一次通过。4.4 心态崩了怎么办——聊聊第29天的情绪管理说实话复习到中间我有过短暂的心态波动。看到自己漏写懒标记下放的时机第一反应是“我是不是白学了”。这种情绪特别可怕它会导致一个恶性循环越觉得自己不行越不敢检测自己越不检测知识漏洞就越隐蔽。我的调整策略是给每次考试式复习加一个“容错提示”。默写模板出现错误时我不会批评自己而是在旁边标一个红色的“补丁”符号然后写出正确的版本。这样一来正确的代码和错误的记忆同时被强化了一次相当于多了一次针对性训练。心态上我还会暗示自己第29天发现漏洞比第90天才发现划算太多了。复习不是寻找自己的失败而是在建立一份“还需要补什么”的清单这份清单本身就是学习进度的一部分。5. 我在第29天踩过的坑和对后续30天的调整5.1 复习时最大的坑误把“重看”当“复习”我在第29天最深刻的体会就是复习的第一原则是提取不是重看。如果你打开上次的笔记从头到尾读一遍感觉自己都懂了那其实是一种幻觉。真正有效的复习应该先盖住笔记逼自己回忆关键词、算法框架、代码结构再打开笔记核对。哪怕回忆出来的是错的也比看一遍有用得多——因为错误的回忆给了你一个明确修补目标而流畅的重看只是给大脑一种“我很熟”的虚假安全。5.2 给后续30天设置的三个新规则踩了坑之后我马上给自己后面的计划调了三个新规则。第一每周末固定做一次“闭卷知识地图”把本周所有涉及的算法全部写在A4纸上不允许翻笔记这个动作强制我每周校准一次记忆第二每次复习最多覆盖三个主题宁可精嚼一个不要走马观花过十个第三建立一个错题复发台账每道错题记录两个字段第一次做错的时间、复习时是否仍然卡壳超过五分钟。如果一道题卡壳超过五分钟说明它根本不是“粗心”而是底层思维链条还断着必须拆碎重写。这第三点其实是这个项目标题背后最重要的经验第29天不是终点而是曲线开始变陡的起点。所有坚持到第29天的人最危险的一件事就是自满最幸运的一件事则是你还有第30天、第60天、第90天可以去修正方向。用0x3f这个编号里的探索精神去面对学习中的不确定性把每一次卡顿都当成更新自己的机会这才是持续进步的真实逻辑。我个人在实际操作中还有一个体会复习日志不必写成大段感想越简短越好。当时做过的题、卡过的点、补上的代码才是复习真正的痕迹。等哪天想偷懒时翻一翻记满问题的日志比喊十遍“加油”都管用。希望这份第29天的复盘记录能给同样在长跑算法学习路上的你一个可以参照的节奏感。
