C++ 竞赛学习路线笔记
一、基础运算与输入输出
1. 基础公式
-
求和:
sum = 0 -
求乘积:
sum = 1 -
交换两个数:
swap(a, b) -
输入整数:
cin >> a -
输出整数:
printf("%d", a);
2. 判断条件
-
n 能被 i 整除:
n % i == 0 -
偶数:
n % 2 == 0 -
奇数:
n % 2 == 1
3. 最值查找
-
最大值:
max = -99999,if(max < ?) max = ? -
最小值:
min = 999999,if(min > ?) min = ?
4. 循环控制
-
统计数量:
cnt = 0; cnt++; -
循环 1~n:
for(int i=1; i<=n; i++){} -
输入 n 个数:
for(int i=1; i<=n; i++){ cin >> x; } -
中断循环:
break -
跳过本轮:
continue -
输入若干数:
while(cin >> n){}
二、数组
1. 一维数组
-
输入 n 个值:
for(int i=1; i<=n; i++) cin >> a[i]; -
倒序输出:
for(int i=n-1; i>=0; i--)
2. 二维数组(n*m 矩阵)
cpp
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
cin >> a[i][j];
}
}
-
主对角线:
i == j -
副对角线:
i + j == n + 1
3. 字符数组 / 字符串
-
字符数组长度:
#include <cstring>,strlen(数组名) -
字符串长度:
#include <string>,变量名.size() -
整行读取:
getline(cin, 变量名) -
截取子串:
s.substr(起始位置, 长度) -
查找字符:
s.find(字符),未找到返回string::npos -
替换内容:
s.replace(起始位置, 长度, 新字符串) -
删除字符:
s.erase(起始位置, 长度) -
插入字符:
s.insert(位置, 字符串) -
转整数:
stoi(s),stoll(s)(long long) -
整数转字符串:
to_string(数字)
三、排序与库函数
1. 排序
-
升序:
sort(数组名, 数组名+长度);需#include <algorithm> -
降序:
sort(数组名, 数组名+长度, greater<int>());
2. 数学函数(#include <cmath>)
-
幂:
pow(2, 10) -
int 绝对值:
abs(-5) -
float 绝对值:
fabs(-5.999) -
平方根:
sqrt(225) -
最大/最小:
max(25, 6),min(25, 6) -
向下取整:
floor(5.9) -
向上取整:
ceil(5.2) -
两点距离:
sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
四、STL 容器(#include <bits/stdc++.h>)
1. vector 动态数组
- 定义:
vector<int> v; - 尾部添加:
v.push_back(值); - 尾部删除:
v.pop_back(); - 访问元素:
v[i]或v.at(i) - 获取大小:
v.size() - 清空数组:
v.clear() - 判空:
v.empty() - 排序:
sort(v.begin(), v.end());
2. map 映射(键值对)
- 定义:
map<string, int> mp; - 插入/修改:
mp["key"] = value; - 访问:
mp["key"] - 查找键:
mp.count("key")(返回0或1) - 遍历:
cpp
for(auto &p : mp){
cout << p.first << " " << p.second << endl;
}
3. set 集合(自动去重+排序)
- 定义:
set<int> s; - 插入:
s.insert(值); - 删除:
s.erase(值); - 查找:
s.count(值)(返回0或1) - 获取大小:
s.size()
4. pair 二元组
- 定义:
pair<int, int> p = {1, 2}; - 访问:
p.first,p.second - 比较:先比first,再比second
五、函数
1. 函数模板
cpp
函数类型 函数名(参数1, 参数2...){
return ?;
}
2. 质数判断
cpp
bool isprime(int n){
for(int i=2; i*i<=n; i++){
if(n%i==0) return false;
}
return true;
}
3. 因子和
cpp
int yinzi(int n){
int sum=0;
for(int i=1; i<n; i++){
if(n%i==0) sum += i;
}
return sum;
}
4. 斐波那契递推式
f[i] = f[i-1] + f[i-2]; (i>=3)
5. 最大公约数 gcd
cpp
int gcd(int a,int b){
if(b==0) return a;
return gcd(b,a%b);
}
五、位运算
-
与:
& -
或:
| -
异或:
^ -
左移:
<< -
右移:
>>
六、常用算法缩写与工具
-
dfs:深度搜索
-
binary_search:二分查找
-
vis:标记数组
-
hanoi:汉诺塔
-
mergesort:归并排序
-
quicksort:快速排序
-
bubblesort:冒泡排序
-
dp:动态规划
-
sizeof:字节数
-
memset:初始化
-
INF:无穷大
-
lower_bound:下限
-
upper_bound:上限
-
even:偶数
-
odd:奇数
七、数据结构
1. 链表 vs 顺序表
-
链表:可插删、不可随机访问
-
顺序表(数组):可随机访问
2. 栈 stack(先进后出)
-
push(值) -
pop() -
top() -
size() -
empty()
3. 队列 queue(先进先出)
-
push() -
pop() -
front() -
back()
4. 二叉树
-
节点 i:左孩子
2*i,右孩子2*i+1 -
先序:根左右
-
中序:左根右
-
后序:左右根
八、算法思想
1. 递推
-
初始化
-
循环写递推公式
2. 递归
-
边界结束
-
自身调用
3. 贪心
-
结构体/数组
-
输入
-
sort 排序
-
循环操作
4. 分治
快速排序、归并排序、二分查找
5. 二分查找模板
cpp
while(l<=r){
int mid = (l+r)/2;
if(a[mid]<x) l=mid+1;
else r=mid-1;
}
6. 动态规划 DP
-
输入
-
初始化状态
-
状态转移方程
-
输出结果
7. DFS 模板
cpp
void dfs(int t){
for(int i=1;i<=运算种数;i++){
if(满足条件){
保存结果/标记;
if(到达目的地){
输出结果;
}else{
dfs(t+1);
}
回溯/清空标记;
}
}
}
8. BFS 模板
cpp
void bfs(){
初始值入队;
标记已用;
while(队列不空){
for(四种方向){
新坐标=队头+方向;
if(越界) continue;
if(合法且未占用){
入队;
标记占有;
}
if(到达终点) 输出;
}
出队;
}
}
九、时间复杂度
-
O(n²):冒泡、插入、选择
-
O(n):桶排序
-
O(n log n):快速排序、归并排序
十、计算机基础
-
1 Byte = 8 bit
-
1 MB = 1024 KB = 1024*1024 B
-
十进制转 X 进制:短除法,倒取余数
-
CPU:运算器 + 控制器 + 寄存器
十二、高精度运算(大整数)
1. 高精度加法
cpp
高精度的加法思想
1.把大数存到字符串;
2.字符串的每个字符数字都通过ASCII转换存到数组,
注意的是要低位存在数组开头:a[i] = s[len-i-1]-'0';
3.获取最大的数长度:max(len1,len2) ;
4.把a,b值加入到c数组: c[i] = a[i]+b[i];
5.c数组加法进位的算式:
① c[i+1] += c[i]/10;
② c[i] %= 10;
6.数字溢出,长度+1;
7.反向输出结果;
2. 高精度减法(a >= b)
cpp
高精度减法的思想
1.输入大数;
2.判断大小,固定s1恒大于s2:
if(s1.size()<s2.size() || s1.size()==s2.size() && s1<s2){
swap(s1,s2); //交换值
cout<<"-";
}
3.获取长度;
4.字符变整数:a[i] = s1[len1-i-1]-'0';
5.减法运算:
if(a[i]<b[i]){
a[i+1]--; //上位--
a[i]+=10; // 本位+10
}
c[i] = a[i]-b[i];
6.去除前导零;
while(c[len1-1]==0 && len1>1){
len1--;
}
7.反向输出;
3. 高精度乘法(大整数 × 小整数)
cpp
高精度的乘法思想
1.把大数存到字符串;
2.字符串的每个字符数字都通过ASCII转换存到数组,
注意的是要低位存在数组开头:a[i] = s1[len-i-1]-'0';
3.获取长度: len = len1+len2-1;
4.乘法进位的算式:
① c[i+j] += a[i]*b[j];
5.c数组的值要进位:
① c[i+1] += c[i]/10;
② c[i] %=10;
5.数字溢出,长度+1;
while(c[len]){
c[len+1] +=c[len]/10;
c[len] %= 10;
len++;
}
6.反向输出结果;
十三、经典例题代码(原样保留)
1. 递推:斐波那契
cpp
#include <bits/stdc++.h>
using namespace std;
int a[1000005], n, x;
int main(){
cin>>n;
a[1]=1;
a[2]=1;
for(int i=3;i<=1000000;i++)
a[i]=(a[i-1]+a[i-2])%1000;
for(int i=1;i<=n;i++){
cin>>x;
cout<<a[x]<<endl;
}
return 0;
}
2. 递归:斐波那契
cpp
#include <bits/stdc++.h>
using namespace std;
long long fbi(int n){
if(n==1||n==2)
return 1;
else return fbi(n-1)+fbi(n-2);
}
int main(){
int n,x;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
cout<<fbi(x)<<endl;
}
return 0;
}
3. 贪心:活动选择
cpp
#include <bits/stdc++.h>
using namespace std;
struct active{
int b,e;
}a[1005];
int n,cnt=1;
bool cmp(active x,active y){
if(x.e!=y.e) return x.e<y.e;
else return x.b<y.b;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i].b>>a[i].e;
sort(a+1,a+n+1,cmp);
int first=a[1].e;
for(int i=2;i<=n;i++){
if(first<=a[i].b){
cnt++;
first=a[i].e;
}
}
cout<<cnt;
return 0;
}
4. DP:数字金字塔
cpp
#include <bits/stdc++.h>
using namespace std;
int a[1005][1005],sum[1005][1005];
int n, max1;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j];
}
}
sum[1][1]=a[1][1];
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++)
sum[i][j]=max(sum[i-1][j],sum[i-1][j-1])+a[i][j];
for(int i=1;i<=n;i++){
max1=max(max1,sum[n][i]);
}
cout<<max1<<endl;
return 0;
}
5. DFS:组合输出
cpp
#include <bits/stdc++.h>
using namespace std;
int n,r,a[1000],cnt;
bool f[1000];
void print(){
for(int i=1;i<=r;i++){
cout<<a[i]<<" ";
}
cout<<endl;
}
void dfs(int t){
for(int i=1;i<=n;i++){
if(a[t-1]<i&&f[i]==0){
a[t]=i;
f[i]=1;
if(t==r){
print();
}
else dfs(t+1);
f[i]=0;
}
}
}
int main(){
cin>>n>>r;
dfs(1);
return 0;
}
6. BFS:细胞
cpp
#include <bits/stdc++.h>
using namespace std;
char a[1005][1005];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
int n,m,cnt;
queue<int>q1,q2;
void bfs(int x,int y){
q1.push(x);q2.push(y);
a[x][y]='0';
while(!q1.empty()){
for(int i=0;i<4;i++){
int tx=q1.front()+dx[i];
int ty=q2.front()+dy[i];
if(tx<1||ty<1||tx>n||ty>m){
continue;
}
if(a[tx][ty]=='1'){
q1.push(tx);q2.push(ty);
a[tx][ty]='0';
}
}
q1.pop();q2.pop();
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>a[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='1'){
cnt++;
bfs(i,j);
}
}
}
cout<<cnt;
return 0;
}