模板
1
2
3
4
5
6
7
8
9
10
11
#include <bits/stdc++.h>// 仅比赛用,其他情况下不建议也可能不支持使用
using namespace std;// 大项目程序不建议使用
int main() {
ios::sync_with_stdio(false); // 加速 禁用stdio.h的代码(C++98不支持使用)
cin.tie(nullptr); // 加速 cin与cout分离
// 代码
return 0;
}
输入与输出
基本输入输出
| 操作 | 代码 | 说明 |
|---|---|---|
| 读整数 | cin >> n; |
自动跳过空格/换行 |
| 读字符串 | cin >> s; |
读到空格停止 |
| 忽略换行符 | cin.ignore(); |
避免后面的getline(cin, s);跳过 |
| 读整行 | getline(cin, s); |
读入空格,前面有cin需加cin.ignore() |
读到,停止 |
getline(cin, s, ','); |
逗号可以换成其他 |
| 输出 | cout << x; |
|
| 换行 | cout << endl; 或 cout << "\n"; |
常见输入模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 先读n,再读n个数
int n; cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
// 读到文件尾
int x;
while (cin >> x) { ... }
// 读带逗号的数据
int a, b;
char comma;
cin >> a >> comma >> b; // 输入 "1,2"
// 读坐标 (x,y)
int x, y;
char ch;
cin >> ch >> x >> ch >> y >> ch; // ch 吃掉括号和逗号
输出格式控制(iomanip)
| 控制符 | 作用 | 示例 |
|---|---|---|
setw(n) |
设置宽度为 n | cout << setw(5) << 123; → " 123" |
setfill(c) |
设置填充字符 | cout << setfill('0') << setw(5) << 123; → "00123" |
setprecision(n) |
设置小数精度 | cout << setprecision(2) << 3.14159; → 3.1(默认模式) |
fixed |
固定小数位数 | cout << fixed << setprecision(2) << 3.14159; → 3.14 |
scientific |
科学计数法 | cout << scientific << 3.14159; → 3.141590e+00 |
left / right |
左对齐/右对齐 | cout << left << setw(5) << 123; → "123 " |
hex / dec / oct |
十六进制/十进制/八进制 | cout << hex << 255; → "ff" |
showbase |
显示进制前缀 | cout << showbase << hex << 255; → "0xff" |
uppercase |
十六进制大写 | cout << uppercase << hex << 255; → "FF" |
boolalpha |
输出 true/false | cout << boolalpha << true; → "true" |
常用 <cmath> 函数速查
幂函数、指数函数与对数
| 函数 | 作用 | 代码示例 |
|---|---|---|
sqrt(x) |
计算平方根 | double result = sqrt(9.0); // 结果为 3.0 |
pow(x, y) |
计算 x 的 y 次方 | double result = pow(2.0, 3.0); // 结果为 8.0 |
exp(x) |
计算 e 的 x 次方 | double result = exp(1.0); // 结果为 e (约 2.71828) |
log(x) |
计算自然对数(以 e 为底) | double result = log(2.71828); // 结果约等于 1.0 |
log10(x) |
计算常用对数(以 10 为底) | double result = log10(100.0); // 结果为 2.0 |
取整与绝对值
| 函数 | 作用 | 代码示例 |
|---|---|---|
fabs(x) |
计算浮点数的绝对值 | double result = fabs(-3.14); // 结果为 3.14 |
abs(x) |
计算整数的绝对值 | int result = abs(-5); // 结果为 5 |
ceil(x) |
向上取整 | double result = ceil(2.3); // 结果为 3.0 |
floor(x) |
向下取整 | double result = floor(2.7); // 结果为 2.0 |
round(x) |
四舍五入取整 | double result = round(2.5); // 结果为 3.0 |
三角函数与反三角函数
| 函数 | 作用 | 代码示例 |
|---|---|---|
sin(x) / cos(x) / tan(x) |
正弦 / 余弦 / 正切(x 为弧度) | double result = sin(3.14159 / 2); // 结果约等于 1.0 |
asin(x) / acos(x) / atan(x) |
反正弦 / 反余弦 / 反正切 | double result = asin(1.0); // 结果约等于 π/2 (1.5708) |
atan2(y, x) |
计算 y/x 的反正切(可确定象限) | double result = atan2(1.0, 1.0); // 结果约等于 π/4 (0.785) |
其他常用函数
| 函数 | 作用 | 代码示例 |
|---|---|---|
fmod(x, y) |
计算 x/y 的浮点数余数 | double result = fmod(5.2, 2.0); // 结果为 1.2 |
hypot(x, y) |
计算直角三角形斜边长 (√x²+y²) | double result = hypot(3.0, 4.0); // 结果为 5.0 |
类和对象
类与对象的关系
| 概念 | 比喻 | 代码 |
|---|---|---|
| 类 | 设计图纸 | class Student { ... }; |
| 对象 | 根据图纸造出的房子 | Student s; |
| 成员变量 | 房子的属性 | string name; int age; |
| 成员函数 | 房子的功能 | void study(); |
定义一个简单的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <string>
using namespace std;
class Student {
public: // 公共访问权限
string name;
int age;
void introduce() {
cout << "我叫" << name << ",今年" << age << "岁" << endl;
}
};
int main() {
Student s1;
s1.name = "张三";
s1.age = 18;
s1.introduce(); // 我叫张三,今年18岁
return 0;
}
访问权限(封装)
| 关键字 | 含义 | 访问范围 |
|---|---|---|
public |
公开 | 类内、类外都能访问 |
private |
私有 | 只能在类内访问(默认) |
protected |
保护 | 类内和子类能访问 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Student {
private: // 私有成员
string name;
int age;
public: // 公有接口
void setName(string n) { name = n; }
string getName() { return name; }
void setAge(int a) {
if (a >= 0 && a <= 150) age = a;
else cout << "年龄无效" << endl;
}
int getAge() { return age; }
};
int main() {
Student s;
// s.name = "张三"; // ❌ 错误,name是private
s.setName("张三"); // ✅ 通过公有函数设置
cout << s.getName(); // ✅ 通过公有函数获取
return 0;
}
构造函数(创建对象时自动调用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Student {
private:
string name;
int age;
public:
// 构造函数:与类同名,无返回值
Student(string n, int a) {
name = n;
age = a;
cout << "学生" << name << "已创建" << endl;
}
void introduce() {
cout << "我是" << name << "," << age << "岁" << endl;
}
};
int main() {
Student s1("张三", 18); // 自动调用构造函数
Student s2("李四", 19);
s1.introduce();
return 0;
}
构造函数重载
1
2
3
4
5
6
7
8
9
10
class Student {
private:
string name;
int age;
public:
Student() : name("无名"), age(0) {} // 无参构造
Student(string n) : name(n), age(18) {} // 单参构造
Student(string n, int a) : name(n), age(a) {} // 双参构造
};
初始化列表(推荐写法)
1
2
3
4
Student(string n, int a) : name(n), age(a) {
// 函数体可以为空
}
// 优点:效率更高,const成员和引用成员必须用初始化列表
析构函数(对象销毁时自动调用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Array {
private:
int* data;
int size;
public:
Array(int n) : size(n) {
data = new int[n]; // 构造函数分配堆内存
}
~Array() { // 析构函数:前面加 ~
delete[] data; // 释放内存
cout << "内存已释放" << endl;
}
};
int main() {
Array arr(100); // 创建
// ...
return 0; // 离开作用域,自动调用析构函数
}
this 指针
this 指向当前对象自己。
1
2
3
4
5
6
7
8
9
class Student {
private:
string name;
public:
void setName(string name) {
this->name = name; // 区分成员变量和参数
}
};
静态成员(属于类,所有对象共享)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Student {
private:
string name;
static int count; // 静态成员变量(声明)
public:
Student(string n) : name(n) {
count++; // 每创建一个学生,计数+1
}
static int getCount() { // 静态成员函数
return count;
}
};
int Student::count = 0; // 静态成员变量定义(必须)
int main() {
Student s1("张三");
Student s2("李四");
cout << Student::getCount() << endl; // 2
return 0;
}
STL
容器(Containers)
1. vector(动态数组)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <vector>
vector<int> v;
// 初始化
vector<int> v; // 空
vector<int> v(n); // n个0
vector<int> v(n, x); // n个x
vector<int> v = {1,2,3}; // 列表初始化
// 操作
v.push_back(x); // 尾部加
v.pop_back(); // 尾部删
v[i] = x; // 下标访问(不检查越界)
v.at(i); // 下标访问(检查越界)
v.size(); // 长度
v.empty(); // 判空
v.clear(); // 清空
v.resize(n); // 重设大小
v.begin(); v.end(); // 迭代器
// 遍历
for (int i = 0; i < v.size(); i++) cout << v[i];
for (int x : v) cout << x;
for (auto it = v.begin(); it != v.end(); it++) cout << *it;
2. deque(双端队列)
1
2
3
4
5
6
7
8
9
#include <deque>
deque<int> dq;
dq.push_back(x); // 尾部加
dq.push_front(x); // 头部加
dq.pop_back(); // 尾部删
dq.pop_front(); // 头部删
dq[i]; // 下标访问
dq.size(); dq.empty(); dq.clear();
3. stack(栈,后进先出)
1
2
3
4
5
6
7
8
#include <stack>
stack<int> st;
st.push(x); // 压栈
st.pop(); // 出栈(无返回值)
st.top(); // 查看栈顶
st.size(); st.empty();
// 注意:stack 不能直接遍历
4. queue(队列,先进先出)
1
2
3
4
5
6
7
8
#include <queue>
queue<int> q;
q.push(x); // 入队
q.pop(); // 出队(无返回值)
q.front(); // 队头
q.back(); // 队尾
q.size(); q.empty();
5. priority_queue(优先队列,最大堆)
1
2
3
4
5
6
7
8
#include <queue>
priority_queue<int> pq; // 大根堆
priority_queue<int, vector<int>, greater<int>> pq2; // 小根堆
pq.push(x); // 插入
pq.pop(); // 删除堆顶
pq.top(); // 查看堆顶
pq.size(); pq.empty();
6. set(集合,自动去重+排序)
1
2
3
4
5
6
7
8
9
10
11
12
#include <set>
set<int> s;
set<int, greater<int>> s2; // 降序
s.insert(x); // 插入
s.erase(x); // 按值删除
s.count(x); // 判断存在(0或1)
s.find(x); // 查找,返回迭代器
s.size(); s.empty(); s.clear();
// 遍历
for (int x : s) cout << x;
7. map(映射,键自动排序)
1
2
3
4
5
6
7
8
9
10
11
12
#include <map>
map<string, int> mp;
mp[key] = value; // 插入/修改
mp.count(key); // 判断键存在
mp.erase(key); // 删除
mp.size(); mp.empty(); mp.clear();
// 遍历
for (auto& p : mp) {
cout << p.first << ":" << p.second;
}
8. unordered_set / unordered_map(哈希表,O(1))
1
2
3
4
5
6
7
#include <unordered_set>
#include <unordered_map>
unordered_set<int> us;
unordered_map<string, int> ump;
// 操作同 set/map,但不排序,更快
9. pair(对组)
1
2
3
4
5
6
7
#include <utility>
pair<int, int> p = {x, y};
pair<int, int> p2 = make_pair(x, y);
p.first; p.second; // 访问
// pair 可直接比较、排序(先first,再second)
迭代器(Iterators)
基本操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vector<int> v = {1,2,3,4,5};
auto it = v.begin(); // 指向第一个元素
auto end = v.end(); // 指向最后一个的下一个位置
*it; // 解引用
it++; it--; // 移动
it + 2; // 随机移动(vector/deque支持)
// 遍历
for (auto it = v.begin(); it != v.end(); it++) {
cout << *it;
} // cpp11+版本
for (vector<int>::iterator it = v.begin(); it != v.end(); it++){
cout << *it;
} // 老版本
迭代器失效
| 操作 | vector | list/set/map |
|---|---|---|
| 插入 | 可能全失效 | 不失效 |
| 删除 | 后面全失效 | 只失效被删的 |
| 扩容 | 全部失效 | - |
1
2
3
4
5
// 正确删除写法
for (auto it = v.begin(); it != v.end(); ) {
if (需要删除) it = v.erase(it);
else it++;
}
算法(Algorithms)
头文件
1
2
#include <algorithm>
#include <numeric>
遍历
1
2
3
4
5
6
7
8
for_each(v.begin(), v.end(), [](int x){
cout << x;
});
// 使用transform前一定要用b.resize(a.size())扩大空间
v2.resize(v.size())
transform(v.begin(), v.end(), v2.begin(), [](int x){
x += 1;
})
排序
1
2
3
4
5
6
7
8
sort(v.begin(), v.end()); // 升序
sort(v.begin(), v.end(), greater<int>()); // 降序
sort(v.begin(), v.end(), [](int a, int b) { // 自定义
return a > b;
});
stable_sort(...); // 稳定排序
partial_sort(...); // 部分排序
nth_element(...); // 找第n大
查找
1
2
3
4
5
auto it = find(v.begin(), v.end(), x); // 线性查找
bool ok = binary_search(v.begin(), v.end(), x); // 二分(有序,超快)
int pos = lower_bound(v.begin(), v.end(), x) - v.begin(); // 第一个 >= x
int pos = upper_bound(v.begin(), v.end(), x) - v.begin(); // 第一个 > x
auto range = equal_range(v.begin(), v.end(), x); // 返回 {lower, upper}
修改
1
2
3
4
5
reverse(v.begin(), v.end()); // 反转
fill(v.begin(), v.end(), 0); // 填充
replace(v.begin(), v.end(), old, new); // 替换
copy(v.begin(), v.end(), back_inserter(v2)); // 复制
rotate(v.begin(), v.begin()+k, v.end()); // 旋转
删除(erase-remove 惯用法)
1
2
3
4
5
// 删除所有值为 x 的元素
v.erase(remove(v.begin(), v.end(), x), v.end());
// 删除满足条件的元素
v.erase(remove_if(v.begin(), v.end(), [](int x){ return x < 0; }), v.end());
排序去重
1
2
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
计数
1
2
3
4
int cnt = count(v.begin(), v.end(), x); // 等于x的个数
int cnt = count_if(v.begin(), v.end(), [](int x){ // 满足条件的个数
return x > 0;
});
最值
1
2
3
int mx = *max_element(v.begin(), v.end());
int mn = *min_element(v.begin(), v.end());
auto [min, max] = minmax_element(v.begin(), v.end()); // C++11
数值(numeric)
1
2
3
4
5
6
7
8
int sum = accumulate(v.begin(), v.end(), 0); // 求和
int sum = accumulate(v.begin(), v.end(), 0LL); // long long 求和
int prod = accumulate(v.begin(), v.end(), 1, multiplies<int>()); // 乘积
vector<int> prefix(v.size());
partial_sum(v.begin(), v.end(), prefix.begin()); // 前缀和
iota(v.begin(), v.end(), 1); // 填充 1,2,3,4,5...
排列
1
2
3
4
5
6
next_permutation(v.begin(), v.end()); // 下一个排列,返回false表示最后一个
prev_permutation(v.begin(), v.end()); // 上一个排列
do {
// 处理当前排列
} while (next_permutation(v.begin(), v.end()));
集合操作(要求有序)
1
2
3
4
5
6
7
vector<int> res;
set_union(a.begin(), a.end(), b.begin(), b.end(), back_inserter(res));
set_intersection(...);
set_difference(...);
set_symmetric_difference(...);
// back_inserter(res)是一个插入迭代器,每次写入时自动调用 res.push_back(),所以不需要提前分配空间。否则使用merge前一定要用v.resize(a.size() + b.size())扩大空间。
merge(a.begin(), a.end(), b.begin(), b.end(), back_inserter(res));
堆操作
1
2
3
4
make_heap(v.begin(), v.end()); // 建堆
push_heap(v.begin(), v.end()); // 入堆(先push_back)
pop_heap(v.begin(), v.end()); // 出堆(再pop_back)
sort_heap(v.begin(), v.end()); // 堆排序
算术仿函数
头文件:#include <functional>
常用的算术仿函数
| 仿函数 | 运算 | 示例 |
|---|---|---|
plus<T> |
加法 + |
plus<int>()(3, 5) → 8 |
minus<T> |
减法 - |
minus<int>()(5, 3) → 2 |
multiplies<T> |
乘法 * |
multiplies<int>()(3, 5) → 15 |
divides<T> |
除法 / |
divides<int>()(10, 2) → 5 |
modulus<T> |
取模 % |
modulus<int>()(10, 3) → 1 |
negate<T> |
取反 - |
negate<int>()(5) → -5 |
实际应用场景
配合 accumulate 求和
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>
#include <numeric>
#include <functional>
using namespace std;
int main() {
vector<int> v = {1, 2, 3, 4, 5};
// 默认求和
int sum = accumulate(v.begin(), v.end(), 0);
// 用 plus 显式求和(等价)
int sum2 = accumulate(v.begin(), v.end(), 0, plus<int>());
// 求乘积
int product = accumulate(v.begin(), v.end(), 1, multiplies<int>());
cout << "和:" << sum << endl; // 15
cout << "积:" << product << endl; // 120
return 0;
}
配合 transform 批量运算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
int main() {
vector<int> a = {1, 2, 3, 4, 5};
vector<int> b = {10, 20, 30, 40, 50};
vector<int> result(a.size());
// 对应位置相加
transform(a.begin(), a.end(), b.begin(), result.begin(), plus<int>());
// result = {11, 22, 33, 44, 55}
// 对应位置相乘
transform(a.begin(), a.end(), b.begin(), result.begin(), multiplies<int>());
// result = {10, 40, 90, 160, 250}
return 0;
}
配合 sort 排序(虽然更常用 greater/less)
1
2
3
4
5
// 降序排序
sort(v.begin(), v.end(), greater<int>());
// 升序排序
sort(v.begin(), v.end(), less<int>());
greater 和 less 也是仿函数,不过它们属于关系仿函数(比较大小),不是算术仿函数。
常用比赛技巧
类型别名
1
2
3
4
using ll = long long;
using pii = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vector<int>>;
二维 vector
1
2
3
4
5
6
7
8
9
10
// 定义 n 行 m 列,全 0
vector<vector<int>> a(n, vector<int>(m));
// 定义 n 行 m 列,全 -1
vector<vector<int>> b(n, vector<int>(m, -1));
// 输入
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> a[i][j];
字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
string s = "hello";
s.length(); s.size(); // 长度
s.empty(); // 判空
s += "world"; // 拼接
s.substr(pos, len); // 截取
s.find("ell"); // 查找,返回下标,找不到返回 string::npos
s.find('e');
if (s.find('x') != string::npos) { ... }
// 转换
stoi("123"); // string → int
stoll("123"); // string → long long
to_string(123); // int → string
// 判断
isdigit(c); isalpha(c); islower(c); isupper(c);
二分(在有序数组上)
1
2
3
4
5
6
7
// 在 vector 上
int pos = lower_bound(v.begin(), v.end(), x) - v.begin();
int pos = upper_bound(v.begin(), v.end(), x) - v.begin();
// 在普通数组上
int* p = lower_bound(a, a + n, x);
int pos = p - a;
常用常量
1
2
3
int INF = 0x3f3f3f3f; // 约 1e9
long long LINF = 0x3f3f3f3f3f3f3f3f;
int MOD = 1e9 + 7;
比赛检查清单
#include <bits/stdc++.h>或需要的头文件using namespace std;int main()不是void mainreturn 0;- 加速
ios::sync_with_stdio(false); cin.tie(nullptr); - 变量初始化(
int sum = 0) - 数组/vector 大小正确
- 输出格式(空格、换行)
- 数据类型(int 够不够?要 long long 吗?)
- 边界条件(n=0, n=1)
比赛常见错误
| 错误 | 原因 | 解决 |
|---|---|---|
| 编译错误 | 变量名拼错、少头文件 | 看第一行错误信息 |
| 运行错误 | 数组越界、除以0、栈溢出 | 检查下标、递归深度 |
| 答案错误 | 输出格式、数据类型 | 检查空格换行、用long long |
| 超时 | 循环太多 | 用二分/set/map优化 |