一些常用技巧的板子和 注意点mark
struct 封装多元组(类似 pair<>、tuple<>)
注意:重载运算符中的大小关系与实际比较意义相反,即 x.first > y.first
表示以维度 first
从小到大排序,x.first < y.first
则表示以维度 first
总是得到当前最大值。
struct T { int first, second, third; friend bool operator <(T x, T y) { return x.first > y.first; } }; priority_queue< T >q;
二分
二分模板一共有两个,分别适用于不同情况。
算法思路:假设目标值在闭区间[l, r]
中, 每次将区间长度缩小一半,当l = r
时,我们就找到了目标值。
case1:找到满足 check() 的区间的左边界,形如 ..........voooooo(. 表示false,o 表示 true,v 表示目标值)
当我们将区间[l, r]
划分成[l, mid]
和[mid + 1, r]
时,其更新操作是r = mid
或者l = mid + 1
;,计算mid
时不需要加1。
int bsearch(int l, int r) { while (l < r) { int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; } return l; }
case2:找到满足 check() 的区间的右边界,形如 oooooov..........
当我们将区间[l, r]
划分成[l, mid - 1]
和[mid, r]
时,其更新操作是r = mid - 1
或者l = mid
;,此时为了防止死循环,计算mid
时需要加1。
int bsearch_2(int l, int r) { while (l < r) { int mid = l + r + 1 >> 1; if (check(mid)) l = mid; else r = mid - 1; } return l; }
实数上的二分
l = 0, r = n + 1; double eps = 1e-6; while (l + eps < r) { double mid = (l + r) / 2; if (check(mid)) r = mid; else l = mid; } return l;
建图去重边
#include<bits/stdc++.h> using namespace std; typedef pair<int, int> PII; struct edge { int yo, w, next; }e[M]; int top, h[N]; int n, m; map<PII, bool> mp; int main() { cin >> n >> m; for(int i = 1; i <= m; i ++) { int x, y; cin >> x >> y; if (mp.count({x, y})) continue; add(x, y); mp[{x, y}] = true; } return 0; }
离散化
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
inline void discrete() { for (re i = 1; i <= n; i ++) b[i] = a[i]; sort(b + 1, b + n + 1); int cnt = unique(b + 1, b + n + 1) - b - 1; for (re i = 1; i <= n; i ++) a[i] = lower_bound(b + 1, b + cnt + 1, a[i]) - b; }
mark 遍历的不同顺序对程序时效的影响
做这道题时发现的玄学优化方法?
-
若用 vector 存图应从右下角开始顺时针遍历;(不存图也要用这种方式)
-
若用 链式前向星 存图应从左上角开始顺时针遍历;
取模运算 mod 相关结论
-
若
, -
若
,
第一个结论显然,主要是证明第二个结论
若
所以 存在
因为
所以
gcd(a, b) 及其相关结论
欧几里得算法求两数的最大公约数,复杂度为
c++ 也有内置函数 __gcd(a,b)
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
有结论
可用于 P8207 [THUPC2022 初赛] 最小公倍树 优化建图的转化
运用 P10463 Interval GCD,通过差分将区修 + 区间 gcd 转化为 点修 + 区间 gcd,而 gcd 刚好也满足差分转换
这里也给出以下简单的证明,新学到的方法,若想证明 A = B,可以分别证明 A ≥ B, B ≥ A
证明:右部 ≥ 左部
设,
则,不妨设为
因为
即
其余可推广同理
所以左部的最大公约数至少是右部的公约数,满足不等关系 证明:左部 ≥ 右部
设
则,不妨设为
因为
即
其余可推广同理
所以右部的最大公约数至少是左部的公约数,满足不等关系
取整与四舍五入
ceil((double)a / b)
向上取整,等价于 公式 x = (a-1)/b+1
, 变形一下得 x = (a+b-1)/b
floor((double)a / b)
向下取整
round((double)a / b)
四舍五入(对小数只保留到整数位),若要保留小数位,假设保留 2 位,则 printf("%.2lf\n", round((double)x * 100) / 100);
快速幂
快速求解幂运算
利用二进制拆分的思想和倍增,如
在拆分的同时,对底数进行平方倍增
inline int quickpow(int a, int b) { int res = 1; while (b) { if(b & 1) res = res * a; a = a * a; b = b >> 1; } return res; }
mark 含减法的取模运算
一定要加上模数再取模!!! (number % mod + mod) % mod
快读快写
数据流比较大时用,这里只能用于整型输入输出
有时候输出可能会甚至爆 unsigned long long
,其实也就只是 long long
的两倍,
此时可以用 __int128
,范围顾名思义,NOI Linux 2.0 已经支持!!!但是要手写输入输出
inline int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = (x << 3) + (x << 1) + c - '0'; c = getchar(); } // x = x * 10 + c -'0' return x * f; } inline void print(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) print(x / 10); putchar(x % 10 + '0'); }
mark 多组不定数据输入单行字符串
形如
abcde fghijk lmnopq
可以用 while (~scanf("%s", c + 1))
,注意不要在里边加 &
其他
油猴 https://www.tampermonkey.net/
cf 翻译 https://greasyfork.org/zh-CN/scripts/465777-codeforces-better
at 翻译 https://greasyfork.org/zh-CN/scripts/471106-atcoder-better
CF-Predictor https://www.crx4chrome.com/crx/46813/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具