代码易错点
写题原则:
看题解还不懂的题不要内耗,自己手动模拟。
有错误先分析错因,再针对调试。
不要无脑写,一边写就要一边注意细节,比如到底是哪个数组,有没有换数组,是 \(n\) 还是 \(m\)。或者一些逻辑上的错误。
代码能力与速度!!!写代码一定要注意细节有没有写错,尤其是变量不要弄错。
-
静态查错一定要认真思考正反细节比如 \(<\) 还是 \(>\),注意输出中间变量,根据输出错误答案猜错因。检查数组 maxs maxn 是否写反。不要觉得看着顺眼/对称就觉得自己是对的,比如线段树合并的是 ls(u) ls(v) 而不是 ls(u) rs(v)。检查的时候可能看着 ls rs 对称就跳过去了。
-
看完题解后不要看题解代码,按照自己理解写,如果要看题解代码的话一定要仔细看别漏。
-
对拍>静态查错,如果小样例出错,先输出中间过程。
-
写代码一定要专注,思考每一步的正确性,注意细节,不要犯低级错误。不可着急去写,要想清楚细节。写的哪怕慢一点也要把结构格式等等写好,方便调试。
-
思考题目注意寻找关键切入点,或者思考题面涉及知识点的相关性质,往可行方案上靠近,切勿盲目思考。
-
注意数据范围,如开不开 long long 或 maxn 大小。
-
检查的时候一定要造特判的样例测试一下,比如别忘记在特判输出里面换行。
-
注意用眼,不思考时合上电脑,眺望远方。
-
调试一定要小心,不要不小心改掉了之前的代码
-
一定要把式子完整列出来,不能空想。
-
不要因为点小就开小数组,可能会有点大的特殊性质。
-
审题,第 K 大 OR 第 K 小。
-
统一形式,多合并相同操作,避免混乱。
-
一定要认真思考对后面有没有影响,或者模拟出过程,不可大概想想。
-
一定要注意看输入格式,或者特殊性质。如 CF314E 题目中给大小写,实则输入只是小写。
-
如果看不懂题解操作,可以自己按题解思路想一下代码,看看实现那个缺什么,缺少的部分就是题解里看不懂的地方。
-
如果看题解一定要认真仔细看,不要漏关键信息。
-
并查集递归可能炸,可以考虑循环写。
-
一定不能忘记判断边界会不会超,可以自己测试极端样例。如 P7960 [NOIP2021] 报数
-
\(\operatorname{set}\) 里面一定要用 s.lower_bound 而非 lower_bound,否则复杂度可能会退化成 \(O(n)\)。
-
P3177 [HAOI2015] 树上染色 注意是加的时候是双向贡献加,减的时候就别忘记除以2,才能保证不被多加。计数的时候可以构造很小的样例自己多试一试。
-
虚拟机上写代码一定要小心,很多错误不报错。比如结构体不命名。函数无返回值。
-
注意题目运行时间,不是 \(1s\)。
-
打擂台法判断最值,记得赋初始值,防止最后没打擂台就结束了。如:P2196
-
define 不保证内部运算先算 AT_arc100_b [ABC102D] Equal Cut
-
位运算优先级比等号低!
-
注意 \(calc(u,v)\) 不可用 \(sz\) 替代,因为无法确保先传 \(sz\) 还是先调用 \(find\) 函数。函数传参一定要小心,注意几个参数之间是否互相关联。
solve(find(v,u),calc(v,u));
-
注意按照我的线段树写法下传区间的时候依然是 \((l,r)\)。
-
多测不要乱 \(memset\)
for(int i=1;i<=n;i++) c[a[i]]=0;
-
维护最大和次大值的时候,如果当前值等于最大值也要更新,因为这样会引起次大值的变大。
-
lld
-
莫队先减后加
-
如果一个地方代码修改,注意与之关联的位置代码也要改。
-
注意弄清树状数组维护的是什么,如果是值域的话,那么更新的上限一直要更新到最大值而非最大下标。
-
如果出现负数需要平移的情况,别忘记数组开两倍
-
多测判断对错,需要等数据输入完再输出 No 并推出,否则会影响下一组
-
P1025 [NOIP2001 提高组] 数的划分 注意记忆化搜索刻画状态的完全性。本题还需要加上前驱的状态。
-
不能用 1 直接左移 \(60\) 位,应该用 1ll。
-
注意各个变量名,不要搞错了
-
int大数相乘注意开long long
-
移动溢出后,按位 \(1\) 结果是 \(1\)。小心!
-
交换 map 是 \(O(1)\) 的。
-
写完一段代码,想给 cpp 文件改名的时候注意先保存当前代码,否则改名后就自动不保存。
-
注意如果映射了值,在其他地方别忘了继续映射
-
快读变量名 x f 不要冲突,记得赋值 x=0 f=1
-
贪心匹配的题目开集合注意要开 muliset。小心不要全部删除了,要删迭代器。
-
不能一边用迭代器访问一边删除集合内元素会造成混乱。
-
取集合末尾元素,--s.end() 而不是 s.end()--
-
f[i]=max(f[i],f[g[j]]+(a[i]&a[g[j]]));
位运算要打括号!!! -
注意输入的数中有无 long long s/p lld 开long long
-
if 条件判断 见寒假模拟赛4总结
-
随机树的树高为 \(\log n\),所以对于随机树暴力从一点到另一点复杂夫为 \(O(\log n)\)。
-
如果卡常,多组数据输入的 \(n\) 和 \(m\) 记得也不能用普通 cin,因为可能 T 很大。
-
如果要一边 dfs 一边判断祖先的话需要判断 dfn 大小而非是否有过,因为可能会出现儿子节点遍历过某个点后,\(u\) 又枚举到了这个点
-
如果线段树右节点的信息依赖于左节点目前的信息,那么就需要先下传右节点,防止左节点信息更新后改变。
-
一定要小心检查各个特判的地方。尤其是考试结束前,统一检查一遍,测一下样例。
-
K-=sz[ch[u][bit]],u=ch[u][bit^1];
一定要注意先后顺序,\(u\) 变了之后减的值就变了。 -
P10217 [省选联考 2024] 季风 一定不要想复杂了,有相同形式的操作合并即可,而且本题绝对值不需要讨论可以直接去,有的时候需要观察性质。
-
无论是文化课还是 oi ,都要注意如果发现一个地方计算或者代码有问题需要更改的时候,注意与之牵连的部分也要更改。
-
扩展域并查集记得初始化不止 \(n\),应该是 \(k\times n\)
-
小心给出的是森林或者不连通图,或者自己图论建模,建出来的不连通
-
决策单调性的题目,如果有 double,但是答案要求取整,决策中的 \(f_i\) 不能取整,否则会破坏单调性质。
-
做除法的时候注意取整,是向上还是向下。如果是向上可以 \(\frac{a-1}{b}+1\)
-
写完程序尤其是出现问题时一定要自己完整小心检查一下小地方,一定要细致检查不可一带而过
-
ll 的时候 inf 0x3f 注意也要开 ll
-
如果循环最后还有一个对于所有情况的处理,不可随便 continue 这样就处理不了最下面的那个更新了。
-
题目不一定升序给出 \(a_i\)
-
扫描线可能无法扫到全局,需要特判
-
for(int j=i;j>=1;j--) b[j]-=b[1];
必须倒着减,否则 \(b_1\) 会改变 -
如果到终点必须停止的话,在可达性统计中不能将终点压入队列,最短路中从队列中取出终点也不能扩展。
-
如果题目中有到达某个点可以使用某条件但是限制使用次数的话,能使用的时候注意不一定使用。
-
一个信息如果要被重复用到的时候,注意不要着急修改。
-
CF1214H Tiles Placement 注意判断是否存在三链共点且两两之和 \(\ge k\) 的时候,不能只看链长是否大于,还需要看看是否有链防止出现 \(0+k \ge k\) 的情况。并且注意由于此时链返回的长度包含根节点,所以注意需要判断的是 \(\neq 1\) 而不是 \(0\)。
-
注意有的时候为了方便处理,有的要求或者值不一定要代入化简式,可能原式更方便。
-
计数问题的边界情况不止是应该考虑数组下标 \(<0\) 的事情,还应该从实际意义角度出发,也就是说有的时候不是因为状态本身不合法,而是从状态 \(A\) 到 状态 \(B\) 这个过程不合法。比如 ABC134F Permutation Oddness 当 \(j\) 为 \(0\) 的时候,无法向前匹配。还有增加匹配。还有就是如果使用了前面的状态需要对其限制,比如本来 \((i,j)\) 只需要满足 \(i \le j\),但是要是转移途中用到 \((i-1,j+1)\) 就需要 \(i-1 \le j+1\)
-
注意优化可行性,P8376 [APIO2022] 排列 中虽然我将贡献式子从 \(2^j(2-1)\) 优化到了 \(2^j(2^i-1)\),但是实际上之前对于 \(k\) 卡得很紧,所以 \(i\) 只能取 \(1\),故优化无效。
-
每用到一个新变量就要把初始化或者清零之类的先写好,防止后面忘记。
-
注意调用的函数的时候传入了一个 K,后续用到函数参数的时候别用 K,而是用对应的参数名。
-
动态开点一定要考虑空空节点,还可能有一个点开了左边但是没开右边。
-
KDT 节点对应数组需要用 \(id(u)\)
-
求凸包,输入 \(n\) 未必是点集大小,要在去重之后重新统计
-
计算几何一定不要用 = 或者 map 判断相等
-
取模情况一下除法一定要记得逆元
-
取模树状数组如果有加上负数操作,一定不要忘记 \(+mod\)
-
不要什么大小都无脑 \(n\)。
-
点分治不要忘记统计重心点。
-
cdq分治优化 dp 注意转移下标要用
a[i].id
。 -
cout<<(ans^1)<<endl;
如果不打括号会报错,^ 和 << 引起歧义。 -
函数调用别忘记写函数名,编译器不报错。
-
平面只要判断两个相对方向,左上和右下的时候不需要二维数点,CF1379F1 Chess Strikes Back (easy version)。只需要记录单维度的最大最小值即可。
-
不要重复用定义变量。
-
memcpy 注意必须类型相同。
-
当值域出现负数,最小值不要设 \(0\)。
-
造成连续多个并列 if 的时候,如果前一个 if 里面的执行语句会造成后面判断条件里的变量改变,那么要用 else if
-
如果下标域里面有 \(0\),那么树状数组无法正常运行,可以考虑整体下标加一,注意初始化的时候要初始到 \(n+1\)
-
多测,后缀和数组一定要记得对 \(n+1\) 清 \(0\),否则 \(suf_{n+1}\) 可能不为 \(0\)。
-
读题一定要仔细,有些全局约束或者保证可能放在最下面的测试点数据栏下面。
-
改了程序,再运行,一定要先编译。
-
\(n,m\) 不要打反。
-
码量题注意速度。
-
要小心如果这么枚举子集不会枚举到空集
for(int i=s;i;i=(i-1)&s)
-
如果要借鉴题解写法,一定先要记录下有哪里常用习惯自己和题解不一样,防止后面写错。
-
\(\operatorname{double}\) 类的最值不要用 0x3f 之类的。
-
整数除法别忘记开 \(\operatorname{double}\)
-
如果统计答案在循环内部,注意可能有边界条件使得不进入循环,要在初始化的时候就统计答案。
-
注意函数传参顺序是否正确,还有结构体传入变量顺序是否正确。一定要在每次传入的时候去原位置看一下是否对应。
-
右移多位是 UB 行为。
-
不要重复定义变量。
-
字符串题记得多测一定要清空 \(s_0~s_{n+1}\)。
-
const double pi=acos(-1.0);
类型不要写错 -
线段树修改和询问的时候一定要小心 \(ql>qr\) 的情况,因为在有的时候某个东西无意义,我们按照常理赋值后传入会导致 \(ql>qr\)。
-
ql=queryg(0,L,R); qr=queryf(0,L,R);
一定要先开其他变量记录,不能用 L,R,否则后续 L 改变导致第二个询问出错。 -
权值线段树一定要考虑有无 \(0\) 出现。异或可能出现 \(0\)。
-
如果二分值域里面有 \(0\),小心 check 函数里面的除法。
-
(V<<2)+10,一定要打括号。
-
if(n%2==1&&(k<n+m-2||k>=n*m)){ cout<<"NIE"<<endl; return 0; } if(n%2==0&&(k<n+m-1||k>=n*m)){ cout<<"NIE"<<endl; return 0; }
注意这个条件判断的写法,不能写 else 然后不判断 \(n \bmod 2=0\),因为可能不满足的是第二个条件。类似 if 要注意。
-
贪心/最优化问题对于结构体排序一定要想如何第一关键字相同,怎么排其他关键字。
-
f[i+L[i]].push_back(i),f[i+R[i]+1].push_back(-i)
像这种下标有加了值得一定要判断是否超出范围 OR 开两倍数组。 -
fc[j]*fc[k]>fc[i]
哪怕是 long long 也不能随便乘,注意数据可能会爆。应该改用除法。 -
位运算的优先级低于等号。
-
用快速幂板子小心遇到 \(0\)。
-
函数返回值类型!!!
-
传参注意变量类型
-
三分必须是严格单调。
-
多测题的特判,一定要等所有数据输入完之后再特判,否则会输入到下一组去。
-
\(\gcd\) 小心遇到 \(0\)
-
删 double 改 int 的时候,一定要注意有没有一个地方这个变量作分母。
-
调试的时候如果要注释语句,一定要在代码开头备注,防止最后忘记加上。
-
多组询问不要随便改参数。
-
交互题记得调用提问函数的结果可能要开 long long。
-
Manacher 除了 \(t\) 数组之外,\(r\) 数组也要双倍。
-
必须进入型和是否操作型不要放到同一个 if 里面。
-
能预处理的尽量都预处理掉,不要中途计算,可能复杂度会增加。
-
多测数据清空问题:有的数组看似不用清空,后面调用某函数的时候会被覆盖,但是可能那个函数不会被调用。
-
vec unique 之后不可 auto
-
每次修改后更新统计的做法,记得初始的更新统计。
-
左右端点离散化,记得开两倍数组。
-
初始化的时候小心大小是 \(n\) 还是 \(m\)。
-
任何相乘都要警惕 1ll
-
注意 \(dp_i\) 是否继承 \(dp_{i-1}\)。有的时候必须继承。 P9871 [NOIP2023] 天天爱打卡
-
如果某个值会变大,那么注意以它为下标的数组必须开大,不可取初始状态。
-
链式前向星边要开两倍,如果边是点的两倍,那么按照点来开要四倍。
-
前后缀 dp,如果是 \(f_{i-1}+g_i\) 的话注意要枚举到 \(n+1\)。
-
欧拉回路,数组大小要开到边级别,而不是点级别,因为一个点会被经过多次。
-
贪心决策中如果一个物品有多次决策,千万别在第一次决策完就插入集合,否则可能会在下次决策的时候决策自己。P1607 [USACO09FEB] Fair Shuttle G
-
部分分暴力枚举的时候记得每次清空,还有 dfs 的时候注意数组能不能能开全局。
-
树 v 图注意树上联通块为整体来 dp 的题,需要在块顶对于所有块内点 dp 一下,不然光光是遍历了某点的子树不能保证整个连通块相连接的点都被访问过了。
-
少用各种变量的判断来判断状态,而是自己单开一个状态记录变量。
-
注意更新顺序 \(A\to B\),一定要确保 \(A\) 已经被更新了。
-
P11191 「KDOI-10」超级演出 有两个“序” 的题目一定要想清楚,一个是图上的遍历顺序,还有一个是 \(a\) 序列的顺序。