惨痛的历史教训

文件名一定要打好

边界情况一定要判(试试 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)\)

手造数据时不要造多个相同数字组成的数据,防止 minmaxnm 写反

\[\frac{1}{(1-x)^n}=\sum\dbinom{n+i-1}{i}x^i \]

求最大值之和的时候注意赋初值

比如 \(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

\[P(A)=\frac{N(A)}{N(\Omega)}\ne\frac{N(A_1)}{N(\Omega_1)}+\frac{N(A_2)}{N(\Omega_2)}+\cdots+\frac{N(A_n)}{N(\Omega_n)} \]

用数字做代号的话改代表的意思时要注意,可以考虑 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 需要读入换行,注意 pythonjoin 并不会在最后换行

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) 得到的不是下标!

带定义域限制的李超树等价于区间插入。

区间插入的李超树必须将中间传下去!

posted @   JerryTcl  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示