Classic Wrongs

Data Structure

  • 线段树 / 可并堆合并,没有写 rt[u] = merge(rt[u], rt[v]),写了 merge(rt[u], rt[v])

  • 0-1 Trie:

    • next[pos][key >> i & 1], 不是 next[pos][key & (1 << i)]!!!
  • 线段树

    • 可能会出现 modify / query 操作中的 \(l > r\) 的情况,这时应小心,在线段树内写上判断或在函数调用前判断是否合法。e.g #2055. 「TJOI / HEOI2016」排序, AC & RE, 注意 check 函数的差别。

    • 注意变量名!尤其是 tr!最好用别的变量名!变量名很容易写错!

    • 如果线段树里是矩阵这类的,最好别开结构体。因为用了结构体后似乎很容易 MLE!最好 \(O(n)\) 建树!e.g. P6021 AC vs MLE.

    • 动态开点如果不要紧,空间能开多大开多大。到底有几次 modify 可能会算错,或根本没算!e.g. P5163, AC vs RE.

    • 动态开点线段树常数极大(离散化后树状数组的效率是其的 \(10\) 倍以上),用之前看看树状数组能不能用。24/12/21 ABC384G 本机调试 sgt 6s, fwk 0.3s.

    • 线段树记得 pushdown。e.g. CF407E

    • 线段树清空的时候,tag[u] = 0 的位置不要放错!e.g. CF407E

    • 动态开点线段树的 \(0\) 号节点的值要设成零元。e.g. QOJ 7884.

  • Persistent Segment Tree

    • 不要吝啬空间,开大一点。AC RE, line 32 & 33.
  • fenwick

    • 树状数组上倍增时注意边界问题!(不要超出上界)e.g. P4137, AC, WA, line 101 & 102.
  • 并查集

    • 并查集一定要启发式合并 + 路径压缩!

    • 启发式合并别把 siz 的初始化忘了/xk e.g. P5163, AC vs TLE, line 4 in main.

  • ST 表

    • 迭代预处理时 rmq[i - 1][j + (1 << (i - 1))] 忘记写后面那个 -1
  • 左偏树

    • 千万不要空的一个 merge(u, v)!应该写成这样:u = merge(u, v)
  • 扫描线

    • 注意线和点的添加顺序!
  • Hash

    • 二维 hash 的方式要这样:\(xC+y \bmod B\),其中 \(B, C\) 是常数。如果只用 \(x \bmod B\) 的话,随随便便就爆掉了。NOI 0216 网格 AC vs TLE.

Math

  • Number Theory

    • 数字批处理因数时再也不要一个一个 \(O(\sqrt{n})\) 了!要么 \(O(n \log n)\) 预处理,要么枚举倍数!

    • \(O(\sqrt{n})\) 分解质因数时要判断最后剩下的数是否是质数。

    • CRT

      • 各种 CRT 最后的结果是一个同余方程的最小非负整数解,并不能代表返回的值是一个确定的数。e.g. P2480 #13
  • 数数

    • 选取顺序不影响种类的计数不能直接乘法原理,需要组合计数。

    • 数数一定要注意不重不漏

  • 概率

    • 注意考虑贡献的独立性。
  • 矩阵

    • \((\min, +)\) 矩阵乘法,单位矩阵是除了对角是 \(0\) 其它都是 \(+\infty\)!千万注意到底要用 \(0\) 还是 \(+\infty\)

    • 如果开了很多矩阵,最好不要用 vector。因为 vector 的空间是预留的!e.g. P6021.

  • 多项式

    • FFT

      • 三次变两次优化,最后是 F[i].imag() / 2

Algorithm

  • DP

    • DP 不初始化

    • 状压 DP 检查状态与地形是否相符时应为 (sta >> i - 1) & 1),写成 (sta >> i - 1)

    • 分组背包注意循环顺序:先枚举组,再枚举空间,最后枚举组里的物品。

    • 斜率优化时可能需要加入一个 \(0\) 号状态表示凸包的起始点。e.g. 「HNOI2008」玩具装箱 因为没这样连 WA 四发。

    • 斜率优化算斜率时可能需要用 long double 把斜率算出来再比较,此时把除法改成乘法来提高精度可能会爆 long long。e.g. 「HNOI2008」玩具装箱这个讨论

    • 你的 DP 在算什么?如何求出最终结果?是 \(dp_n\),还是 \(\max dp\) 之类?e.g. ABC353G

    • 滚动数组记得状态的继承。

  • Search

    • 对于 DFS,不要觉得某些变量、数组不用清零。能清零就清零!example: P1074, line 58

    • 如果二分的上界达到 \(10^9\),那 \(l, r, mid\) 都要开 long long

  • Binary Lifting

    • 采用与树上倍增类似的思想进行倍增时,请注意倍增数组里肯能有 \(0\) 表示不存在的情况,这种时候可能要不管这个 \(0\)。e.g. WA AC, line 51.
  • Binary Search

    • 二分范围要稍微调大一点,保证答案正确。建议至少调大 \(50\)。e.g. ABC346F 看最新 \(6\) 发提交倒数 \(10\) 来行 \(r\) 的初始值

Gragh

  • BCC & SCC

    • 缩点后,CC 之间可能存在大量重边,这些重边必须去重!不然当 DFS 时,我们会因访问同一个节点多次而 TLE。example: CF1000E

    • 该打标记表示已经访问过的点忘记打标记。

    • 缩点后点的数量是 bcc / scc 而不是 n

    • 缩点后做拓扑排序,如果终点确定,要不管终点的路径上不会存在的 SCC。#2590

    • 对原图进行一定操作后(如删边、缩点),再进行某些统计时,不能用原图(ve G[N]),应该用操作后的图(如 ve DAG[N])。

  • Bipartite Graph

    • 「常错」 二分图最大匹配时,不要忘记 ++dfn。e.g. AC WA line 62.
  • MST

    • Kruskal 重构树的所有数组都要开两倍!e.g. #2718 AC RE, line 41.
  • Other

    • 遇到负边权要谨慎。

    • 你的边数可能不是输入的 \(m\)!比如有时你除了输入的边外又加了一些边!e.g. P7624, line 5 in check.

Tree

  • LCA

    • 求 LCA 时,for (int i = LOGN - 1; ~i; i--) 写成 for (int i = 0; i < LOGN; i--),后一种是错的!example: AC WA
  • Heavy-light Decomposition

  • 点分树

String

  • Other

    • string 的拼接是很慢的!要先 resize 再一个一个填入!e.g. manacher, AC vs TLE.

STL / std 函数 / 一些语法

  • vector 的下标应该从 \(0\) 开始,别手滑打成 \(1\)

  • 使用 vector 时请用 fsanitize 检查越界,防止神秘问题。 普通模式下是看不出来的!

  • stackdeque 底层是一个东西,当你开 \(10^6\)stackdeque 时,你将……需要 4GB 的空间以及……爆零……这时,应该换成 vectorlist

  • 如果想从 priority_queue 里删掉不满足某些条件的元素,不能直接 while(!Q.empty() && Q.top() ... ) Q.pop(),这样的话可能堆顶刚好满足,但堆的其它元素却不满足,然后就寄了。

  • setmultiseterase(T x) 都是把和 X 相等的元素全部删除。如果要控制,需要 eg.erase(eg.find(x))

  • memset 时,如果你想清空前 \(n\) 个数,请先想一想,你使用的是下标为 \([0, n)\) 的数组还是 \((0, n]\) 的。不然其实你没有清空干净。e.g. #2562. 「SDOI2018」战略游戏 AC & WA, line 185(倒数 11 行)

  • 基于范围的 for 循环一定要加上 &!不然根本做不了丝毫修改!e.g. AC vs strange error.

  • 检查你 sortcmp 有没有写错!要是比较方式错了 / 打错了字符可能导致 RE!

  • 注意 rbeginprevnext 和正常迭代器是反过来的!

计算几何

  • 扫描线

    • 扫描线要注意加删东西的顺序,哪个先做?e.g. AC vs WA, solve().

杂项

离线

  • qn 别写反!e.g. ABC393F, AC vs WA, 最后双指针里写错了.

策略

  • 想完一个做法不会想另一种。Turing Cup #6(2024) 因此输麻了,A 题都没过(优先队列比二分还好写)。

  • 想出一个做法前一定要检验正确性!

多测

  • 多测要读完再进行操作。e.g. AC vs RE, line 70~80.

  • 清空不完毕,爆零两行泪。e.g. CF2025E, AC vs WA, val 没清空. 求求了,多 memset 几下不会死的/ll

  • 一定要测书规模乱序的情况!e.g. 上面那个例子,把样例复制两遍后直接 WA 掉.

Other

  • 三年 OI 一场梦,不开 long long 见祖宗

  • nmijuv 写反。

  • 「常错」 数组开小(可能还会 \(\mathsf{ \color{red}WA}\))。数组还是很有必要开大的

  • 没测极限数据,long long 也爆了。要测极限数据!example: P3868

  • 「常错」 做法太复杂。

  • 没删调试信息。

  • 忘记映射了,即把下标当成了需要的值。e.g. #3785 AC WA, line.83 & 87.

  • 把代码粘贴后忘记把一些细节改掉。 e.g. #2195 AC WA, line 109 & 114.

  • \(\min\) 要赋初值,有负数时求 \(\max\) 要先赋 \(-\infty\)

  • 不要用 read()long long!记得用 readl()

  • 搞随机的时候,uniform_int_distribution < int > gen(1, (ull) - 1)。(ull 赋值到 int

  • 时刻牢记你是 index-0 还是 index-1!e.g. ABC366E, AC vs WA, line 108.

  • 注意 \(<\) 还是 \(\le\)?你的写法针对了哪一种?

  • 对拍完一定要测样例!不然可能爆零了!

  • 如果用一个 bool 数组记录答案行不行,而且答案分很多方面计算,那么注意每一次都是 ok[i] |= clause!如果写成了 ok = clause…… e.g. ABC385D, AC vs WA.

  • long double 的精度其实比 double 要高。e.g. ABC385F, AC vs WA.

  • 如果是 index-0 的数组,一些辅助数组的初始值可能是 \(-1\)。e.g. CF407E

  • 变量最好要全部初始化!尤其模板里,不然你也不清楚这个变量最后是局部的还是全局的!e.g. 25/1/23 treap 模板里 ch 没初始化,调了 45min+。

  • 如果要把坐标转化成 index,且一行有 \(m\) 个数,那么 \(id = (x - 1)\red m + y - 1\),而不是 \((x - 1)n + y - 1\)。e.g. P2774, AC vs WA.

  • 千万不要偷懒混用 coutprintf!千万!不然什么输出顺序,你不知道!e.g. P6054, AC vs WA.

  • 「常错」 不要试图去改编某个功能的一个部分实现另一个功能(比如线段树,加个 s == t 的特判做别的事)。e.g. QOJ 7884, Code, 看 void insert 旁边的字.

  • 取模不要忘记处理负数!

  • 能取模的地方都!要!取!模! e.g. CF1336E1, AC vs WA.

posted @   sihiazi  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示