cpp入门
基础模板
以下是我的常用模版
1 |
|
#include"bits/stdc++.h":万能头包含了算法竞赛常用的各种库#define endl '\n':由于endl换行会强制刷新缓冲区导致输出变慢所以一般换行用\n但是我习惯写endl所以有了这个宏定义(这是个坏习惯)ios::sync_with_stdio(0); cin.tie(0), cout.tie(0);:加快数据的输入和输出(较为关键,可大大提升程序读取和输出数据的速度)
由于很多题目都是有多组测试的,便有了一下模板,在solve()函数里写单组的解
1 | int t = 1; |
输入输出
在算法竞赛中,数据的读写是最基本的操作。虽然我们在模板里已经对 cin 和 cout 进行了加速,但有些特定场景下的读写细节依然需要重点掌握。
基础读写
1 | int a, b; |
格式化输出
1 | double ans = 3.14159; |
读取包含空格的字符串
普通的cin >> s遇到空格或者回车就会停止。如果题目给的字符串本身就包含空格(比如 “ H e l l o W o r l d “),你需要用到 getline:
1 | string s; |
注:如果在getline之前使用了cin >>读取其他数据(比如数字)cin会把数字后面的回车符留在缓冲区里,导致getline读到一个空串。这时候需要在中间加一句cin.ignore(); 或者手工吃掉那个回车。
如下:
1 | int n; |
循环读取直到文件末尾 (EOF)
有些题目没有告诉你一共有多少组测试数据,只会说“读到文件末尾为止”。此时可以这样写:
1 | int n; |
结构体 (Struct) 与自定义排序
当你需要将多个相关联的数据打包在一起时(比如二维平面上的坐标 $(x, y)$,或者包含学号、成绩的学生信息),就需要用到结构体。在竞赛中,结构体最常见的应用场景是配合自定义排序。
结构体的定义与基本用法
1 | struct Node { |
结构体排序
详见sort函数的内容
C++ STL 标准模板库入门
STL(Standard Template Library)是 C++ 给大家准备好的“高级数据结构轮子”。熟练掌握它们,能让你省去几百行手写数据结构的代码。在竞赛中,所有的 STL 容器都被包含在了万能头文件 #include <bits/stdc++.h> 中。
超级元组:pair
当结构体里只有两个简单变量时,我们可以直接用 pair,它自带排序规则(优先比较第一个元素,相同再比较第二个),非常适合存坐标或键值对。
1 | pair<int, int> p1; |
动态数组:vector
不知道数组到底有多长时使用。它在图论中存图(邻接表)时是无可替代的神器。
1 | vector<int> v; //定义一个vector类型的变量,可以理解为数组 |
erase的用法
1 | vector<int> v = {10, 20, 30, 40, 50}; |
注意,erase的时间复杂度是O(n)
set系列
普通set
set内部基于红黑树实现,扔进去的元素会自动按升序排序,并且自动去重。所有增删改查的时间复杂度都是 O(log n)。
1 | set<int> s; |
1 | set<int> s = {10, 20, 30, 40}; |
multiset
和set类似,但是可以存重复的元素
1 | multiset<int> ms; |
注意:erase(v)会删除容器内所有值为v的元素,如果只想删除一个的话则可以用以下的方法
1 | multiset<int> ms = {10, 10, 10, 20}; |
字典/映射:map
你可以把 map 看作是一个超级数组,它的下标不再局限于数字,可以是字符串、浮点数,甚至是另一个结构体,它同样基于红黑树,单次操作复杂度为 O(log n)。并且会按key的值排序
1 | map<string, int> mp; // 建立 字符串 -> 整数 的映射 |
如果普通的数组下标就能解决问题(比如范围在 1e7 以内),千万不要用 map!map虽然方便,但 O(log n) 的常数非常大
栈
后进先出
1 | stack<int> st; |
队列
普通队列
先进先出
1 | queue<int> q; |
优先队列
最大/小的数先出
1 | // 1. 默认是大根堆(最大的元素在前面) |
双端队列 (deque)
支持在头部和尾部同时进行快速插入和删除,并且支持像数组一样用下标访问。
1 | deque<int> dq; |
算法竞赛常用的函数
在算法竞赛中,C++ 标准库(STL)和一些内置函数能帮我们省去大量手写基础算法的时间。熟练掌握它们是提速的关键。以下是竞赛中最常碰到的几个核心函数:
排序函数sort
默认是升序排序,时间复杂度是 O(n log n)
1 | int a[100]; |
在很多题目中,默认的升序排序并不能满足需求。比如我们要对结构体进行多重条件排序,或者想降序排列,就需要自己定义一个比较函数(一般命名为 cmp),把它作为第三个参数传给 sort。
cmp 函数的核心逻辑是:如果函数返回 true,就表示第一个参数应该排在第二个参数前面。
基础降序排列
1 | // 自定义比较函数:降序 |
结构体多关键字排序
这就是我们在前面结构体小节提到的核心应用。假设我们有一个学生结构体,要求:先按成绩从高到低排;如果成绩相同,再按学号从低到高排。
1 | struct Student { |
在编写 cmp 函数时,绝对不能写 <= 或 >= 当比较的两个元素相等时,必须严格返回 false。如果你写了 return a >= b;,当遇到大量相同元素时,sort 内部的指针极易越界,导致程序直接崩溃报错。永远只写 <、>、!= 或 == 的组合逻辑。
二分查找lower_bound和upper_bound
这两个函数必须在有序数组或有序容器中使用,能以 O(log n) 的时间复杂度极快地查找到边界。
lower_bound:返回第一个大于等于查找值的元素地址(或迭代器)。upper_bound:返回第一个严格大于查找值的元素地址(或迭代器)。
1 | int a[5] = {1, 2, 2, 4, 5}; |
杂项函数
1 | int x = 10, y = 20; |
注意:max和min函数的两个参数类型必须一致
总结与进阶建议
这篇文章整理了算法竞赛中最基础、最高频的语法和 STL 容器工具箱。但请记住,这仅仅是带你走出了“新手村”,C++ 的特性和算法世界的深奥远不止于此(比如 string 的高级处理、位运算的奇技淫巧、更底层的常数优化等)。
在接下来的集训和日常刷题中,给几个核心建议:
- 多看大佬的代码: 竞赛圈有一句老话:“读别人的好代码,是提升代码常数和编码思维最快的方式。” 在 Codeforces、洛谷或 Vjudge 上 AC(通过)一道题后,千万不要马上关掉页面!去翻一翻排行榜,看看那些运行时间极短、代码极简的大佬是怎么写的。你会慢慢学到很多神奇的 STL 用法、优雅的宏定义以及极其高效的实现逻辑。
- 拒绝死记硬背,靠肌肉记忆: 编程是一门手艺活,语法和模板看十遍不如自己对着题目敲一遍。一开始总是忘记
lower_bound怎么拼写或者cmp怎么写是很正常的,多写几次遇到报错、多调试几次,慢慢就会变成你的本能。 - 拥抱 Bug,关注细节: 遇到 WA(答案错误)、TLE(超时)或 RE(运行错误)时不要崩溃。绝大多数新手的坑都在于:数据范围超出
int忘了开long long、多组测试数据忘了清空数组或容器。耐心 debug 的过程,就是你硬实力提升的过程。
算法竞赛是一场厚积薄发的马拉松。前期的基础打得越牢,代码写得越熟练,后期学复杂的图论、动态规划和高级数据结构时就能越专注在“算法思维”上,而不是被“语法”绊倒。





