Point 1
\(\text{CodeForces - 543D Road Improvement}\)
正确写法:
for(int i = suf[u].size() - 2; i >= 0; -- i)
错误写法:
for(int i = suf[u].size() - 2; ~i; -- i)
原因是 ~\(i\) 只能判断 \(-1\) 的情况。
Point 2
关于类 set, map 的东西,如果把结构体装在里面的话,需要把 所有元素都设一个偏序,否则可能出现不相同的两个数据被去重。
Point 3
今天才知道两个数据类型相乘并不是得到前面的数据类型?而是得到 精度更高 的类型。以后还是要小心这类转换吧。
Point 4
对于边的遍历:
void dfs(int u) {
vis[u]=1; siz[u]=1;
erep(i,u) {
if(vise[i]) continue;
vise[i]=1;
dfs(v);
ans+=w[i]; siz[u]+=siz[v];
ans1=u,ans2=v;
}
}
这样不是 \(\mathcal{O(n)}\),应该还差得远。因为会有回退,判断时还会遍历边。
Point 5
判断到达叶子节点直接 \(\rm return\)(前向星)。
曾经的写法:
if(nxt[head[u]] == 0) return;
其实就是判断是否只有一条边连接。然而……根节点也可能出现这种情况,然后就凉了。
正解:
bool flag = 0;
for(int i = head[u]; i; i = nxt[i]) if(to[i] != fa) DP(to[i], u), flag = 1;
if(! flag) return;
Point 6
依稀记得这个错误在写 \(\text{fwt}\) 的时候也踩过。
当模数为 \(998244353,10^9+7\) 之类大质数时,不能直接写:ans = (x*2+y)%mod
,会爆 int(很弱智是不是)。
哈哈,最近犯了个差不多 sb 的错误 😅😅😅。差不多是做 \(a\times b\)(\(a,b\) 均为 long long),结果 \(b\) 没有取模,然后就寄了 😅😅😅。
Point 7
明明我知道这件事……但真的调起来很救命啊 〒▽〒!
关于 \(\text{memset},\text{memcpy}\) 这一类函数,最后是 \(\text{sizeof(type)}\cdot \rm len\) 啊!啊!啊!
今天手写 \(\rm bitset\) 调得想哭😢。
Point 8
2020 牛客 NOIP 赛前集训营-S(第一场)- C 牛牛的凑数游戏
Point 9
关于高精除的问题。调这个锅直接去世。
fep(i,p,1) a[i-1]+=a[i]%div*10,a[i]/=div;
while(p>1&&a[p]==0) --p;
你会发现,\(a[0]\) 存的是真正的余数乘 \(10\),所以一定要记得除。
Point 10
我真的要哭了!调了这么 jb 久,结果是倍增数组下标写反了,焯!
此时无声胜有声!
Point 11
\(\text{random_shuffle()}\) 记得加随机化种子!
Point 12
发现结构体初始化函数 \(\text{node}()\{\dots\}\) 如果名字和此结构体名字不一样也不会报编译错误?
然鹅就不会给你初始化……
还有一件奇葩事是结构体内可以开不定长数组,但是会跑得贼慢……
Point 13
想题之前记得算一遍样例。
Point 14
注意自己设的极值不要加爆了。
Point 15
至今未弄懂结构体……
在这题\(\text{ 22pts }\)wa 成 sb.
然后发现这样写在洛谷都是 wa 的:
struct buy {
int s, v, t;
buy():s(),v(),t(){}
buy(int S, int V, int T):s(S),v(V),t(T){}
};
或
struct buy { int s, v, t; buy() {} buy(const int S, const int V, const int T) {s = S, v = V, t = T;}};
真的很绝望。
然后这两种都是可以过的:
struct buy {
int s, v, t;
void init(int S,int V,int T) {
s=S; v=V; t=T;
}
};
或
p[i]=(buy){...};
关键是上面 4 种写法在 \(\sf darkbzoj\) 里都是对的 🙃。
以后还是直接写函数吧 🙃。
Point 16
使用这两个函数之前要排序!
\(\text{upper_bound(begin,end,val)}\):从数组的 \(\rm begin\) 位置到 \(\text{end}-1\) 位置二分查找第一个大于 \(\rm val\) 的数字,找到返回该数字的地址,不存在则返回 \(\rm end\).
\(\text{lower_bound(begin,end,val)}\):同理,为大于等于。
注意减的时候减去开始位置。
另外与其联动的还有 \(\text{unique()}\) 函数,需要注意它并不会 真正删除 重复的数值(使用之前也 需要排序)。所以如果想用 \(\rm auto\) 的话,对于 vector 还要加一个:\(\text{vec.erase(unique(values.begin(), values.end()), values.end())}\).
另外结构体使用 \(\rm unique()\) 需要注意要重载 ==
号!
Point 17
写数据结构时要判断节点是否为空。
Point 18
回收节点请全部清零。
Point 19
一定要给 bool 变量赋初值!
Point 20
关于结构体内存对齐。
- 除了第一个成员变量,其他变量要对齐到 对齐数 的整数倍的地址处。
- 对齐数:编译器默认对齐数与该成员大小的较小值。在 \(\rm linux\) 中默认对齐数为 4.
- 结构体总大小为最大对齐数的整数倍。
比如这个结构体:
struct node {
char a;
double b;
int c;
};
最终就是这样:
当然在实际生活中可以直接用 \(\rm sizeof\) 嘛。
Point 21
虽然可能没有什么用……但这个错误真的找了很久……
我的代码 在这组数据上会错,原因是不去括号与前面的符号没法提前算。
!(F|F)|(V)
再放一个比正解还要麻烦的 数据生成器。
Point 22
在写有返回值的函数时,请注意是否有调用下一层函数后需要改变的值。
Point 23
负数在用 \(/x\) 时是向零取整。
Point 24
关于三目运算符:
condition?do A,do B:do C,do D;
此条语句的意思是如果满足条件就做 \(\text{A, B}\),反之做 \(\text{C, D}\).
不过事实上,编译器会判定成这条语句:
(condition?do A,do B:do C),do D;
也就是说无论如何都会做 \(\rm D\)。解决方案是将它们括起来。
Point 25
这个真的傻了。在 \(\sf Luogu\) 上 MLE 疯了,结果其实是数组没开够。
(╯‵□′)╯︵┻━┻
还有,一条线段在线段树上分成的区间个数是 \(2\log n\) 的。
Point 26
我最终还是写了如何算内存。
或者直接用 \(\rm sizeof\),算出来的是 \(\rm B\).
Point 27
\(\text {Dev-C++}\) 很神奇的一点就是不会将这个玩意报错:
inline Max(int x,int y) {
return x>y?x:y;
}
然后就成功 CE 了。
Point 28
用 STL 时,在减小迭代器时一定要记得检验是否为 \(\rm begin()\)!
Point 29
对于 string 类型,+=
相当于扩位操作,一开始只有赋值足够的位数,才能在后面使用 []
赋值与访问。
Point 30
血的教训!前向星的 \(\rm head\) 数组以后都清 \(-1\) 了!抱着一个 \(\rm dijkstra\) 模板调到哭!
Point 31
做有标号的题目时,要时刻记住前后是否排序,标号是否正确。
Point 32
按理来说不是坑的……但调太久了必须放在这儿警醒自己。
关于扫描线:将元素离散化之后必须用一个点维护一段区间(比如点 \(1\) 维护 \([1,2)\)),对于节点 \([l,r]\) 应维护区间 \([h_l,h_{r+1})\),否则会出现 \(\text{mid}\) 与 \(\text{mid}+1\) 之间的区间没有被维护的情况。
Point 33
汗如雨下了属于是 😅。
\(\text{POJ - 1742 Coins}\) 明明是 \(\mathcal O(nm)\) 的单调队列优化 \(\mathtt{dp}\),结果 TLE 麻了。
跟我说这个跑完全和 01 背包不行我就认了,结果还是 TLE。笑死,最后把队列改成数组就过了,这什么 ** 玩意儿。
后记:一次模拟赛又被队列常数卡了,以后感觉卡常就手写循环队列吧 qwq.
Point 34
\(\rm NaN\)\(\neq\)\(\rm NaN\)!
具体可以看 这个,简略地说就是零与无穷、无穷与无穷看似计算出 \(1,-1,0\) 这种数都会导致 \(\rm NaN\).
Point 35
在 vector 的遍历过程中加入元素,就像凌晨三点的 emo,就像鱼在陆地上无法呼吸……希望你永远也不要懂我的痛……💔
Point 36
不要在循环中定义 string 或 vector 之类未经编译器优化的类型,否则会降低运行效率。
Point 37
例如宏定义
# define min(x,y) (x)<(y)?(x):(y)
# define
的实现与函数的实现机制不同,只是简单的代码替换,所以若参数 \(x\) 为函数,在计算的过程中会被调用两次,这在递归函数的使用中是非常致命的。
Point 38
血的教训*2!非 void 函数一定要写返回值,不然可能会出现很奇怪的问题,这时你的代码会像一坨屎一样好调。
Point 39
在用阶乘求组合数时一定要判断 是否存在逆元!一种容易被忽视的情况是 \(p\) 为质数,但是 \(n\) 可能大于 \(p\),此时要用 \(\rm Lucas\) 定理计算组合数。
Point 40
我真的要吐了,今天调一道整体二分的板子题调了整场比赛,不知道自己在写什么,最后发现自己对线段树的理解一直有问题 —— 左半拉明明是更大的!焯!
Point 41
是右边的光头强贡献的菜品:对于某个函数的特判,一定要分清先后顺序!就比如线段树的无解与叶子节点的优先级问题。
Point 42
血的教训*3!我就问你,"\(\text{[BZOJ 4212] }\)神牛的养成计划",对得起我们吗?一个可持久化 \(\rm trie\) 的锅都测不出来,日内瓦退钱 🤬!
在插入字符串时,结束字符一定还要继承祖先的儿子!否则先插入 UU
再插入 U
,之后的插入根本不会统计 UU
这个前缀!
void ins(int ID) {
int n=str[pa[ID]].length(), pre=rt[ID-1], p;
p = rt[ID] = ++cnt; sz[p]=sz[pre]+1;
for(int i=0;i<n;++i) {
int d=co[str[pa[ID]][i]];
for(int j=0;j<4;++j)
if(j^d) t[p][j]=t[pre][j];
t[p][d] = ++cnt;
sz[t[p][d]] = sz[t[pre][d]]+1;
pre=t[pre][d], p=t[p][d];
}
for(int j=0;j<4;++j) t[p][j]=t[pre][j];
}
Point 43
线段树区间操作要记得判断 \([L,R]\) 区间是否满足 \(L\le R\),不然会出很多玄学错误 qwq.
Point 44
竟然现在才写出来这个锅!最好将 \(\rm root\) 的深度和空节点的深度进行区分,否则可能会发生奇怪的问题。
e.g. 倍增求 \(\rm lca\) 就会跳出 0.
Point 45
最近新创了很多菜品昂 qaq!其实也犯过很多次了,就是计算出 \(\displaystyle s=\prod a_i\),想要逆推一些 \(a_i\) 的乘积,一定要注意 是否有逆元!更具体地说,一定要注意是否存在 \(a_i=0\)!