惨痛的历史教训
文件名一定要打好
边界情况一定要判(试试 0,1,MaxN)
数组空间一定要开够,看好 MaxN
多组数据要清空
一定要手摸一遍样例,特别对于交互题或通信题等无法直接测样例的情况
for(scanf("%d", &q); q && scanf("%d", &n); --q) {
for(int i = 1; i <= n; ++i) scanf("%d", a + i)
for(int i = 1; i <= n; ++i) if(a[i] < a[r]) r = i;
// if r > n and a[r] is greater than a[i],
// then the answer will be wrong
printf("%d\n", a[r]);
}
long long 相关:
int j = 1ll * i * i;
// convert long long(1ll * i * i) to int(j)
int Mt(int x) { return (x % Mod + Mod) % Mod; }
Mt(1ll * i * j);
// convert long long(1ll * i * j) to int(x)
int t[x];
void add(int x, int v) { while(x <= n) t[x] += v, x += x & -x; }
// a[i] <= 1e9, but t[x] may be not
long long t[N << 2], d[N << 2];
void add(int x, int v) { t[x] += v, d[x] += v; }
void pushup(int x) { t[x] = max(t[x << 1], t[x << 1 | 1]); }
void pushdown(int x) { if(d[x]) add(x << 1, d[x]), add(x << 1 | 1, d[x]), d[x] = 0; }
// convert long long(d[x]) to int(v)
void change(int x, int v, int l, int r, int L, int R) {
if(l == L && r == R) return add(x, v);
// it seems that add(int, int) is enough
int M = (L + R) >> 1; pushdown(x);
if(r <= M) change(x << 1, v, l, r, L, M);
else if(l > M) change(x << 1 | 1, v, l, r, M + 1, R);
else change(x << 1, v, l, M, L, M), change(x << 1 | 1, v, M + 1, r, M + 1, R);
pushup(x);
}
t[i] = (26ll * h[i] - h[i + 1]) % p * m % p;
// 26ll * h[i] - h[i + 1] may be a negative number
void Inc(int &x, int y) { x += y; if(x >= Mod) x -= Mod; }
// (x + y) should be in [0, 2 * Mod - 1]
Inc(x, y - z + Mod);
// if x, y, z are in [0, Mod - 1],
// then (x + y - z + Mod) can be in [1, 3 * Mod - 2]
线段树相关:
仔细检查大小写与拼写
不要直接赋值 tag
,考虑原 tag
所带的影响
记得 pushup
pushdown
后记得清 tag
区间赋值 tag
初始化为 inf
想好了再写
不要着急否定一个解答,想想有没有改进的可能
一定要初始化完全
for(int i = 1; i < n; ++i)
scanf("%d", d + i), dis[i][i] = 0;
// dis[n][n] is not initialized
// find the minimum k and the second minimum l
(k > w[i]) && (l = k, o = i, k = w[i]),
// k may have been changed !!!
(k > w[i]) || ((l > w[i]) && (l = w[i]));
for(int j = 0; j < (int)d[i].size(); ++j)
for(int k = j + 1; k < (int)d[i].size(); ++k)
if(l <= j && k < i)
// use the index instead of the value
ans -= j + k <= i;
for(int j = 0; j < (int)d[i << 1].size() && d[i << 1][j] < i; ++j)
for(int k = j + 1; k < (int)d[i << 1].size(); ++k)
if(l <= d[i][j] && d[i][k] < i)
// use the wrong value
ans -= d[i][j] + d[i][k] > i;
unordered_map 也要用 count 来检测元素的有无,否则可能 TLE
判断数列是否单峰时要注意连续的相同数字
int check() {
// WA on 5 2 2 2 5
for(int i = 2; i < n; ++i)
if(a[i - 1] > a[i] && a[i] < a[i + 1]) return 0;
return 1;
}
int check() {
// WA on 1 1 2 3
p1 = 1, p2 = n;
while(p1 < n && a[p1] < a[p1 + 1]) ++p1;
while(p2 > 1 && a[p2] < a[p2 - 1]) --p2;
return p1 == p2;
}
int check() {
// AC Code
p1 = 1, p2 = n;
while(p1 < n && a[p1] <= a[p1 + 1]) ++p1;
while(p2 > 1 && a[p2] <= a[p2 - 1]) --p2;
puts(p1 >= p2 ? "YES" : "NO");
}
树上倍增维护点权信息注意顶点
int query(int x, int y) {
// AC Code
// mn[x][i] := min p in [x, fa[x][i]) : v[p]
int res = 0x3f3f3f3f;
if(dep[x] < dep[y]) swap(x, y);
for(int i = 20; i >= 0; --i)
if(dep[fb[x][i]] >= dep[y]) res = min(res, mn[x][i]), x = fb[x][i];
if(x == y) return min(res, mn[x][0]);
for(int i = 20; i >= 0; --i)
if(fb[x][i] != fb[y][i])
res = min(res, mn[x][i]), x = fb[x][i], res = min(res, mn[y][i]), y = fb[y][i];
return min(min(res, mn[x][1]), mn[y][1]);
}
单调队列先加数再删数,因为可能新加进来的数不满足条件
M_PI,M_E 可能 CE
在树上路径转移时先向上转移,再向下
不要分不清二四象限(想想单位圆是怎么转的)
算生成函数时注意常数项,
如取值范围 \([1, k]\) 时,
是 \(x+x^2+x^3+\cdots+x^k\) 而不是 \(1+x+x^2+\cdots+x^k\)
分块时最后一段的空余个数是 \((m-(n\bmod m))\bmod m\),
而不是 \(n\bmod m\) 或 \(m-(n\bmod m)\)
手造数据时不要造多个相同数字组成的数据,防止 min
,max
或 n
,m
写反
求最大值之和的时候注意赋初值
比如 \(a\) 集合为空,则 \(\max\{a\}=-\infty\) 或特判
否则可能 \(\max\{a\}+\max\{b\}=\max\{b\}\ge ans\)
有关乘法时 \(\infty\) 特判
否则 \(\infty=1e9\times1<1e5\times1e5\)
离散化记得维护输入输出
求数的积,求逆元记得考虑零
当没有加法时才可以考虑维护 \(aw^b\)
haha,有加法也可以,直接维护 \(aw^b+cw^d=(aw^{b-d}+c)w^d\qquad(b\ge d)\)
非唯一输出记得确认输出格式,如输出操作数等
预留足够时间打暴力,不要对手速过于自信
\(a, b\le n\),\(a\oplus b\le2^{\lfloor\lg(n)\rfloor}\)
要区分离散化前后的数据范围,如一些题目需要求离散化后的值再乘组合数,那组合数要预处理到原本的范围
要对复杂度有自信,数组要开够,不要只开到觉得能得到的部分分的范围
如果 check 完一个数后要输出这个数,要注意这个数是否已经改变
while(q) {
if(v[q % B]) goto failed;
v[q % B] = 1, q /= B;
}
// q = 0 !!!!
printf("%lld", q);
分类讨论时要注意每一类都要有输出
如果题目给的名称比较抽象,可以考虑使用其实际意思命名
Trie 树插入时记得更新根/叶子节点的 sz
记得观察有没有 Mod,是否需要取模
取模函数不要写错
void Inc(int &x, int y) { if((x += y) >= Mod) x -= y; }
记得区分节点编号和 dfs 编号,修改和查询记得用 dfn
邻接矩阵记得 G[i][i] = 0
差分约束记得边权取 min
用数字做代号的话改代表的意思时要注意,可以考虑 define
不要轻视除法和取模有多慢,保险起见,1s
足够:
int
级别乘法取模 \(1.5\times10^8\) 次long long
不用__int128_t
乘法取模 \(1.2\times10^8\) 次long long
用__int128_t
乘法取模 \(3\times10^7\) 次
淀粉质记得处理只有一个点或链长为 \(0\) 的情况
子集卷积 \(|S| = 2 ^ n\),多项式 \(\deg = n\),长度为 \(n + 1\)
树链剖分记得跳链时是比较 top
的深度
for(; top[u] != top[v]; u = fa[top[u]]) {
if(dep[u] < dep[v]) swap(u, v);
// right: if(dep[top[u]] < dep[top[v]]) swap(u, v);
Chg(1, id[top[u]], id[u], c, 1, n);
}
\(n\) 次插值需要 \(n + 1\) 个点值
比较字符串大小的时候不要只比较 \(<\)!> ``
for(int i = 0; i < len; ++i) {
if(str1[i] < str2[i]) swap(str1, str2); break;
// right: if(dep[top[u]] < dep[top[v]]) swap(u, v);
Chg(1, id[top[u]], id[u], c, 1, n);
}
很多时候 checker
需要读入换行,注意 python
的 join
并不会在最后换行
fout.write('\n'.join(map(str, ans))) # bad
fout.writelines(map(lambda x: str(x) + '\n', ans)) # good
欧拉回路记得当前弧和判连通性
前/后缀 \(\max\) 的单位元不一定是 \(0\)!
for(int i = n; i >= 0; --i) c[i] = g[i];
for(int i = n - 1; i >= 0; --i) c[i] = max(c[i], c[i + 1]);
// wrong: for(int i = n; i >= 0; --i) c[i] = max(g[i], c[i + 1]);
假如想用空集代表全集,要记得判断是否可能出现空集
三目运算符与逗号的优先级一定要记清!
*find(p.begin(), p.end(), v)
得到的不是下标!
带定义域限制的李超树等价于区间插入。
区间插入的李超树必须将中间传下去!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话