① 文件头模板(点按钮一键复制)
万能头版(比赛最常用)推荐
一个 #include <bits/stdc++.h> 包揽所有头文件,不用背。大多数 OJ(洛谷、CSP 认可的平台)都支持。
#include <bits/stdc++.h>
using namespace std;
int main() {
return 0;
}
② 常用数据类型定义范围
2.1 整数类型
| 类型 | 关键字 | 字节 | 范围 | 大约能存多大 |
|---|---|---|---|---|
| 短整型 | short | 2 | −32768 ~ 32767 | ±3 万 |
| 整型 | int | 4 | −2147483648 ~ 2147483647 | ±21 亿(≈2.1×10⁹) |
| 长整型 | long long | 8 | −9223372036854775808 ~ 9223372036854775807 | ±9.2×10¹⁸ |
| 无符号整型 | unsigned int | 4 | 0 ~ 4294967295 | 0 ~ 42 亿 |
| 无符号长整型 | unsigned long long | 8 | 0 ~ 18446744073709551615 | 0 ~ 1.8×10¹⁹ |
📌 范围公式:n 字节有符号范围是 −2^(8n−1) ~ 2^(8n−1)−1。
2.2 浮点 / 字符 / 布尔
| 类型 | 关键字 | 字节 | 有效精度 / 说明 |
|---|---|---|---|
| 单精度浮点 | float | 4 | 约 6~7 位有效数字(少用,易精度丢) |
| 双精度浮点 | double | 8 | 约 15~16 位有效数字(浮点题首选) |
| 长双精度 | long double | 12/16 | 约 18~19 位有效数字 |
| 字符 | char | 1 | −128 ~ 127;一个字母/数字占 1 字节(ASCII) |
| 布尔 | bool | 1 | 只有 true(1)和 false(0) |
2.3 竞赛常用大数常量
| 常量 | 值 | 建议写法 / 用途 |
|---|---|---|
| int 最大值 | 2147483647 | INT_MAX(求最小值时当"哨兵"初值) |
| int 最小值 | −2147483648 | INT_MIN(求最大值时当哨兵初值) |
| long long 最大值 | ≈9.22×10¹⁸ | LLONG_MAX |
| "无穷大" | — | const int INF = 0x3f3f3f3f;(≈10.6 亿,图论常用) |
| 圆周率 | 3.14159265358979… | const double PI = acos(-1.0); |
③ 取值范围记忆口诀 & 选题技巧
3.1 一眼判断用 int 还是 long long
| 题目数据范围写着 | 结论 |
|---|---|
| n ≤ 10⁴(1 万) | int 稳够,n² = 10⁸ 也可跑(勉强) |
| n ≤ 10⁵(10 万) | int 够;但 n² = 10¹⁰ 会超时,想 O(n log n) |
| n ≤ 10⁹(10 亿) | 数值超 int 范围的边缘,乘法/求和必炸 → 用 long long |
| 数值到 10¹⁰ ~ 10¹⁸ | 必须 long long |
| 数值超过 10¹⁸ | long long 也装不下 → 高精度(用字符串/数组模拟) |
⚠️ 两个 int 相乘(如 10⁵ × 10⁵ = 10¹⁰)会先在 int 里溢出再赋值,结果就是错的!要写成
(long long)a * b,先转型再乘。3.2 好记的口诀
- 🔢 int 21 亿:约 2.1×10⁹,记作「十位数」——只要数字不超过 10 位(9,999,999,999 以内)int 就危险了,10 位数一律上 long long。
- 📏 long long 9×10¹⁸:19 位数字封顶,记「十九个 9」。
- ⏱️ 复杂度表(1 秒约跑 10⁸~10⁹ 次简单运算):
n 的规模 能接受的复杂度 n ≤ 20 O(2ⁿ) 搜索 / 枚举子集 n ≤ 500 O(n³) n ≤ 5000 O(n²) n ≤ 10⁵ ~ 10⁶ O(n log n) 或 O(n) n ≤ 10⁸ 只能 O(log n)、O(√n)、O(1)
④ STL 常用速查
4.1 容器一览
| 容器 | 是什么 | 常用操作 | 复杂度 |
|---|---|---|---|
vector<int> v; | 动态数组 | v.push_back(x) / v.size() / v[i] | 尾部插入 O(1) |
set<int> s; | 自动排序+去重 | s.insert(x) / s.count(x) / s.erase(x) | O(log n) |
map<string,int> m; | 键值对(按键排序) | m[key] = val / m.count(key) | O(log n) |
priority_queue<int> q; | 大根堆 | q.push(x) / q.top() / q.pop() | O(log n) |
queue<int> q; | 队列(BFS 用) | q.push(x) / q.front() / q.pop() | O(1) |
stack<int> st; | 栈(DFS/括号匹配) | st.push(x) / st.top() / st.pop() | O(1) |
pair<int,int> p; | 成对数据 | p.first / p.second / make_pair(a,b) | — |
📌 小根堆写法:priority_queue<int, vector<int>, greater<int>> q;
4.2 algorithm 常用函数
| 函数 | 作用 | 示例 |
|---|---|---|
sort | 排序(默认升序) | sort(v.begin(), v.end()); |
max / min | 取大 / 取小 | max(a, b) |
swap | 交换 | swap(a, b); |
reverse | 翻转 | reverse(v.begin(), v.end()); |
lower_bound | 第一个 ≥ x 的位置(需已排序) | lower_bound(v.begin(), v.end(), x) - v.begin() |
upper_bound | 第一个 > x 的位置(需已排序) | upper_bound(v.begin(), v.end(), x) - v.begin() |
__gcd | 最大公约数 | __gcd(a, b) |
abs | 绝对值 | abs(a) |
fill | 数组整体赋值 | fill(dp, dp + n, 0); |
4.3 降序排序 + 自定义排序
// 降序排序
sort(v.begin(), v.end(), greater<int>());
// 按结构体某个成员排序(例如按分数从高到低)
struct Stu { int score; string name; };
sort(stu, stu + n, [](const Stu &a, const Stu &b) {
return a.score > b.score; // a 排在 b 前面返回 true
});
⑤ 常用算法小模板
5.1 二分查找(手写版)
int lo = 0, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] == target) { /* 找到 */ break; }
else if (a[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
5.2 快速幂(a^b % p)
long long qpow(long long a, long long b, long long p) {
long long res = 1;
a %= p;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
5.3 判断质数
bool isPrime(int n) {
if (n < 2) return false;
for (int i = 2; (long long)i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
5.4 埃氏筛(1~n 全部质数)
vector<bool> vis(n + 1, false);
vector<int> primes;
for (int i = 2; i <= n; i++) {
if (!vis[i]) {
primes.push_back(i);
for (long long j = (long long)i * i; j <= n; j += i)
vis[j] = true;
}
}
5.5 BFS 网格最短路(四方向)
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
queue<pair<int,int>> q;
q.push({sx, sy});
vis[sx][sy] = true;
while (!q.empty()) {
auto [x, y] = q.front(); q.pop();
for (int d = 0; d < 4; d++) {
int nx = x + dx[d], ny = y + dy[d];
if (nx >= 0 && nx < n && ny >= 0 && ny < m
&& !vis[nx][ny]) {
vis[nx][ny] = true;
dis[nx][ny] = dis[x][y] + 1;
q.push({nx, ny});
}
}
}
5.6 前缀和 & 差分
// 前缀和:求区间 [l, r] 的和 pre[0] = 0; for (int i = 1; i <= n; i++) pre[i] = pre[i-1] + a[i]; // 区间和 = pre[r] - pre[l-1] // 差分:区间 [l, r] 整体加 c d[l] += c; d[r + 1] -= c; // 最后一遍前缀和还原
⑥ 新手避坑清单
- 💥 溢出:看到 10⁵ 以上的数相乘/累加,先想
long long。乘法写(long long)a * b。 - 📂 文件 IO:CSP/NOIP 上机考试必须写
freopen,文件名和题目完全一致,忘了=0 分。 - 🔢 数组开小:数组大小 = 题目上限 + 5(防止差分/边界越界),如
a[100005]。 - 🔁 死循环:while 循环检查循环变量一定会变化;二分的 mid 计算写
lo + (hi - lo) / 2防溢出。 - 🧹 多组数据:多测试点的题(如 n 组询问),数组、变量每组都要清零/重置。
- 🔤 读带空格的整行:用
getline(cin, s),注意它前面如果有cin >> x要先cin.ignore()吃掉换行。 - 🖨️ 输出格式:看清题目要求——行末多余空格、大小写、保留小数(
printf("%.2f", x))都可能判错。 - ⏱️ 对拍自查:写完先用样例测,再自己造极端数据(最小值、最大值、全相同、边界)测一遍。
- 💾 long long 输出:printf 要用
%lld,cout 则直接输出即可。 - 🧊 变量初始化:全局数组自动清零,局部数组是随机值,必须手动初始化!
🔒 随手记(密码保护)
设置一个随手记密码
首次使用请创建密码。笔记会用 AES-GCM 加密后保存在本机浏览器里,没有密码谁也看不到(包括你自己)。