## C++ 入门防爆零教程(上册)
######  C++ Introductory Explosion Proof Zero Tutorial(Volume $1$)
编写者:美公鸡(洛谷账号:beautiful_chicken233,电话:$155****7747$,如有需要请随时联系)
编写时间:$2023.10.5 \sim ?$
地址:湖南省长沙市雨花区明升异城 $11$ 栋 $3902$
出版社:美公鸡出版社
价格:$0.38$ 元
### Part $0$ 目录
###### Directory
##### Part $1$ 赛时注意事项
###### $...$ Part $1.1$ 文件读写
$.....$ Part $1.1.1$ $\texttt{freopen}$
$.....$ Part $1.1.2$ $\texttt{fstream}$
$.....$ Part $1.1.3$ $\texttt{fopen}$
###### $...$ Part $1.2$ 源程序的存放
###### $...$ Part $1.3$ 恶意程序
###### $...$ Part $1.4$ 卡常
$.....$ Part $1.4.1$ 关闭同步流
$.....$ Part $1.4.2$ 关闭缓冲区自动刷新
$.....$ Part $1.4.3$ 快读快写
$.....$ Part $1.4.4$ 底层优化
##### Part $2$ 算法
###### $...$ Part $2.1$ 时间 & 空间复杂度
$.....$ Part $2.1.1$ 时间复杂度
$.....$ Part $2.1.2$ 空间复杂度
###### $...$ Part $2.2$ 枚举
###### $...$ Part $2.3$ 模拟
###### $...$ Part $2.4$ 排序
$.....$ Part $2.4.1$ 选择排序
###  Part $1$ 赛时注意事项
###### Games-time precautions
#### Part $1.1$ 文件读写
在 CSP 等重大比赛中,最重要的就是文件读写,在每一年都有许多竞赛选手因为文件读写而爆零。而文件读写都很多类,比如 `freopen` 等等。下面介绍的是 $3$ 种常用的文件读写。
##### Part $1.1.1$ $\texttt{freopen}$
在程序中加上 $\texttt{freopen("xxx.in/out", "r/w", stdin/stdout);}$ 之后,程序就会从 $\texttt{xxx.in}$ 中读取输入文件,在 $\texttt{xxx.out}$ 中输出。
##### Part $1.1.2$ $\texttt{fstream}$
首先需要在主函数外面定义 $\texttt{\#include <fstream>}$ 头文件和 $\texttt{ifstream fin("xxx.in")}$ 和 $\texttt{ifstream fout("xxx.out")}$。然后在程序中要文件读写的写成 $\texttt{fin}$ 和 $\texttt{fout}$ 即可。
##### Part $1.1.3$ $\texttt{fopen}$
首先要定义 $\texttt{FILE *file = fopen("xxx.in", "r+/w+")}$。然后在程序中使用 $\texttt{fscanf(file, "", ...)}$ 和 $\texttt{fprintf()}$ 即可。
#### Part $1.2$ 源程序的存放
在比赛中,源程序的存放是比较重要的,源程序的错误存放会导致失去分数。
一般的存放结构如下:
$\texttt{|-your name (folder)}$
$\texttt{|---T1 name (folder)}$
$\texttt{|------T1 name.cpp}$
$\texttt{|---T2 name (folder)}$
$\texttt{|------T2 name.cpp}$
$\texttt{|---T3 name (folder)}$
$\texttt{|------T3 name.cpp}$
$\texttt{|---T4 name (folder)}$
$\texttt{|------T4 name.cpp}$
#### Part $1.3$ 恶意程序
在比赛中,恶意程序的分数会变为 $0$,且会有相应的惩罚,**一定不要做**。
恶意程序的杀伤力如下表:
| 代码 | 杀伤力 |
| :-----------: | :-----------: |
| $\texttt{while (1) \& Sleep()}$ | 低 |
| $\texttt{system("")}$ | 中 $\sim$ 高 |
| $\texttt{\#include <con>}$ | 极高 |
### Part $1.4$ 卡常
##### Part $1.4.1$ 关闭同步流
C++ 的输入输出的缓冲区和 C 是同步的,我们可以用 $\texttt{ios::sync\_with\_stdio(0)}$ 关闭同步流而加快速度。
##### Part $1.4.2$ 关闭缓冲区自动刷新
程序会在输入和输出时刷新缓冲区(特别是 `endl`,想快一点就用 `'\n'`),我们可以用 $\texttt{cin.tie(0), cout.tie(0)}$ 关闭缓冲区自动刷新而加快速度。
##### Part $1.4.3$ 快读快写(不推荐,比较麻烦)
**模板:**
快读:
```cpp
int read() {
  int s = 0, f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    (ch == '-') && (f = -1), ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    s = (s << 1 + s << 3) + ch - '0', ch = getchar();
  }
  return s * f;
}
```
快写:
```cpp
void write(int x) {
  (x < 0) && (putchar('-')) && (x = -x);
  if (x > 9) {
    write(x / 10);
  }
  putchar(x % 10 + '0');
}
```
##### Part $1.4.4$ 底层优化
**循环展开:**
恰当的循环展开可以让 CPU 多线程进行并发运算,可以提升速度。但是不恰当的循环展开可能会起副作用。
展开前:
$\texttt{for (int i = 1; i <= 300; ++ i) \{}$
$\texttt{  ans += i;}$
$\texttt{\}}$
展开后:
$\texttt{for (int i = 1; i <= 300; i += 6) \{}$
$\texttt{  ans += i;}$
$\texttt{  ans += i + 1;}$
$\texttt{  ......}$
$\texttt{  ans += i + 6;}$
$\texttt{\}}$
**火车头(指令优化):**
Tips:**NOI 禁止。**
$\texttt{\#pragma GCC optimize(3)}$
$\texttt{\#pragma GCC target("avx")}$
$\texttt{\#pragma GCC optimize("Ofast")}$
$\texttt{\#pragma GCC optimize("inline")}$
$\texttt{\#pragma GCC optimize("-fgcse")}$
$\texttt{......}$
完整代码:
```cpp
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#pragma GCC optimize(2)
```
###  Part $2$ 算法
######  Algorithm
#### Part $2.1$ 时间 & 空间复杂度
##### Part $2.1.1$ 时间复杂度
人们将程序运行次数的量级以及空间的量级成为时空复杂度,用大 $O$ 表示,一般会忽略常数。现代评测机大约每秒能够运行 $2 \times 10^7 \sim 10^9$ 次,但是使用了数组就比较慢了。需要**格外注意**你的时间复杂度是否都在题目限制以内。
**时间复杂度表:**
| 时间复杂度 | 少爷评测机 | 老爷评测机 |
| :-----------: | :-----------: | :-----------: |
| $O(\log n)$ | $2^{10^9}$ | $2^{2 \times 10^7}$ |
| $O(\sqrt n)$ | $10^{18}$ | $4 \times 10^{14}$ |
| $O(\log n\sqrt n)$ | $5 \times 10^{14}$ | $3 \times 10^{11}$ |
| $O(n^{\frac{3}{4}})$ | $10^{12}$ | $5 \times 10^9$ |
| $O(n)$ | $10^9$ | $2 \times 10^7$ |
| $O(n \log \log n)$ | $4 \times 10^8$ | $5 \times 10^6$ |
| $O(n \log n)$ | $4 \times 10^7$ | $10^6$ |
| $O(n \sqrt n)$ | $10^6$ | $8 \times 10^4$ |
| $O(n^2)$ | $3 \times 10^4$ | $5000$ |
| $O(n^2 \log n)$ | $9000$ | $1500$ |
| $O(n^2 \sqrt n)$ | $4000$ | $1000$ |
| $O(n^3)$ | $1000$ | $300$ |
| $O(n^4)$ | $150$ | $80$ |
| $O(n^5)$ | $60$ | $30$ |
| $O(2^n)$ | $30$ | $25$ |
| $O(2^n \times n)$ | $25$ | $20$ |
| $O(n!)$ | $12$ | $10$ |
| $O(n! \times n)$ | $11$ | $9$ |
| $O(n^n)$ | $9$ | $8$ |
**常用时间复杂度排序:**
$O(1) < O(\log n) < O(\sqrt n) < O(n) < O(n \log n) < O(n \sqrt n) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)$
##### Part $2.1.2$ 空间复杂度
类似地,算法所使用的空间随输入规模变化的趋势可以用空间复杂度来衡量。
如,开一个长度为 $n$ 的数组,那么空间复杂度是 $O(n)$。开一个长度为 $n \times n$ 的二维数组,那么空间复杂度是 $O(n^2)$。开一个长度为 $n \times 3$ 的二维数组或 $3$ 个长度为 $n$ 的数组,那么空间复杂度是 $O(3n)$。开一个长度为 $n$ 的数组和一个长度为 $m$ 的数组,那么空间复杂度是 $O(n + m)$。
#### Part $2.2$ 枚举
枚举的思想是不断地猜测,从可能的集合中一一尝试,然后再判断题目的条件是否成立。但是并非所有的情况都要枚举,有时要适当的进行一些剪枝。(如枚举 $a + b = c$ 且 $b > a$ 的个数那么 $b$ 要从 $a + 1$ 开始枚举)。
**例题:**
给出 $n$ 个数 $a_1, a_2, \cdots, a_n$ 和 $x$,求有多少对 $i, j$ 满足 $a_i + a_j = x$ 且 $j > i$。
输入样例:
```cpp
6 12
4 5 7 6 3 5 6
```
输出样例:
```cpp
2
```
数据范围:$1 \le n \le 10^3$,$1 \le x, a_i \le 10^9$。
分析:
我们可以先枚举 $i$,从 $1$ 枚举到 $n$。每次枚举到一个 $i$ 时枚举 $j$,从 $i + 1$ 枚举到 $n$(因为 $j > i$)。每枚举到一个 $i, j$ 时判断条件 $a_i + a_j = x$,如果满足把答案 $+1$。时间复杂度 $O(n^2)$。(准确来说是 $O\Big(\dfrac{n^2 - n}{2}\Big)$)。
代码:
```cpp
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
using ll = long long;
const int kMaxN = 1010, kInf = (((1 << 30) - 1) << 1) + 1;
int n, x, a[kMaxN], ans = 0; // ans 是满足条件的个数
int main() {
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
  cin >> n >> x; // 输入 n, x
  for (int i = 1; i <= n; ++ i) {
    cin >> a[i]; // 输入 ai
  }
  for (int i = 1; i <= n; ++ i) { // 枚举 i,范围 1 至 n
    for (int j = i + 1; j <= n; ++ j) { // 枚举 j,范围 i + 1 至 n
      (a[i] + a[j] == x) && (++ ans); // 如果 ai + aj = x,那么答案 +1(if 压缩)
    }
  }
  cout << ans << '\n'; // 输出答案
  return 0;
}
```
#### Part $2.3$ 模拟
模拟就是用代码模拟出题目所要求的操作。虽然本质上比较简单,但是码量大,很难调错。所以做模拟题的时候一定要先构思好再敲代码。
**例题:**
小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 $1970$ 年 $1$ 月 $1$ 日 $00:00:00$ 到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。
数据范围:给定的时间不超过 $10^{18}$。
分析:
我们直接把输入的时间 $t$ 除以 $1000$ 变成秒(毫秒和秒之间的进率为 $1000$)。然后再时间转换,天为 $t \bmod (60^2 \times 24) \div 60^2$,小时为 $t \bmod (60^2 \times 24) \bmod 60^2 \div 60$,分钟为 $t \bmod (60^2 \times 24) \bmod 60$。这里为了方便,我们定义 $d = 60^2 \times 24$,$h = 60^2$,$m = 60$。时间复杂度 $O(1)$。注意,一定要开 `long long`!
代码:
```cpp
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
using ll = long long;
const int kMaxN = -1, kInf = (((1 << 30) - 1) << 1) + 1;
const ll d = 24 * 60 * 60, h = 60 * 60, m = 60; // 定义常量 d, h, m
int main() {
//  freopen(".in", "r", stdin);
//  freopen(".out", "w", stdout);
  ll t;
  cin >> t; // 输入 t
  t /= 1000; // 把 t 除以 1000(把毫秒转换成秒)
  ll day = t % d / h, hour = t % d % h / m, _min_ = t % d % m;
  // 计算天,小时,分钟(注意这里 min 只能定义成 _min_)
  printf("%02d:%02d:%02d", day, hour, _min_); // 输出,格式为 dd:hh:mm
  return 0;
}
```
#### Part $2.4$ 排序
**凉心提醒:这一章比较长。**
排序就是将一个无序的序列排成有序的算法,下面为各个排序的性质:
| 排序算法 | 时间复杂度 | 空间复杂度 | 稳定性 | 特殊性质 |
| :-----------: | :-----------: | :-----------: | :-----------: | :-----------: |
| 选择排序 | $O(n^2)$ | $O(1)$ | 否 | 可以通过额外的 $O(n)$ 空间达到稳定 |
| 冒泡排序 | $O(n) \sim O(n^2)$ | $O(1)$ | 是 | 有序时速度快,可以进行剪枝 |
| 插入排序 | $O(n) \sim O(n^2)$ | $O(1)$ | 是 | 当 $n$ 较小时速度很快 |
| 快速排序 | $O(n \log n) \sim O(n^2)$ | $O(\log n) \sim O(n)$ | 否 | 最快的排序,有序时退化到平方级 |
| 归并排序 | $O(n \log n)$ | $O(n)$ | 是 | 不易被卡,很稳定 |
| 希尔排序 | $O(n) \sim O(n^2)$ | $O(1)$ | 否 | 是插入排序改进而来的排序 |
| 堆排序 | $O(n \log n)$ | $O(1)$ | 否 | 常数较大 |
| 桶排序 | $O(\max^{n}_{i = 1} a_i)$ | $O(n + m)$ | 是 | 空间比较大 |
| 基数排序 | $O(d(r + n))$ | $O(rd + n)$ | 是 | 非比较排序 |
| 计数排序 | $O(n + k)$ | $O(k)$ | 是 | 非比较排序 |
##### Part $2.4.1$ 选择排序
选择排序的思想就是在无序区里找到最大值,然后与无序区的最后一个交换位置,再把无序区的最后一个变成有序区。当有序区有 $n - 1$ 个元素时,排序完成。
例:(绿色代表有序区)
初始:$[5, 7, 2, 8, 4]$
第 $1$ 次:$8$ 最大,与 $4$ 交换位置,$[5, 7, 2, 8, 4] \gets [5, 7, 2, 4, \green{8}]$。
第 $2$ 次:$7$ 最大,与 $4$ 交换位置,$[5, 7, 2, 4, \green{8}] \gets [5, 4, 2, \green{7}, \green{8}]$。
第 $3$ 次:$5$ 最大,与 $2$ 交换位置,$[5, 4, 2, \green{7}, \green{8}] \gets[2, 4, \green{5}, \green{7}, \green{8}]$。
第 $4$ 次:$4$ 最大,与 $4$ 交换位置,$[2, 4, \green{5}, \green{7}, \green{8}] \gets[2, \green{4}, \green{5}, \green{7}, \green{8}]$。
排序后:$[2, 4, 5, 7, 8]$。
代码:
```cpp
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
using ll = long long;
const int kMaxN = 5050, kInf = (((1 << 30) - 1) << 1) + 1;
int n, a[kMaxN]; // 定义 n 和 a 数组
int main() {
  cin >> n; // 输入 n
  for (int i = 1; i <= n; ++ i) {
    cin >> a[i]; // 输入 ai
  }
  int maxa = -1e9, idx = 0; // 存最大值,idx 是下标
  for (int i = n; i >= 2; -- i) {
    maxa = -1e9; // 每次取最大值前要把 maxa 赋值成极小值
    for (int j = 1; j <= i; ++ j) { // 枚举最大值
      if (a[j] >= maxa) { // 如果大于等于最大值
        maxa = a[j], idx = j; // 更新最大值
      }
    }
    swap(a[idx], a[i]); // 交换位置
  }
  for (int i = 1; i <= n; ++ i) {
    cout << a[i] << ' '; // 输出
  }
  cout << '\n';
  return 0;
}
```

C++ 入门防爆零教程(上册)的更多相关文章

  1. Spring Boot 2.0 的快速入门(图文教程)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! Spring Boot 2.0 的快速入门(图文教程) 大家都 ...

  2. MyBatis学习总结-MyBatis快速入门的系列教程

    MyBatis学习总结-MyBatis快速入门的系列教程 [MyBatis]MyBatis 使用教程 [MyBatis]MyBatis XML配置 [MyBatis]MyBatis XML映射文件 [ ...

  3. Git入门基础详情教程

    前言 写了一篇文章<一篇文章了解Github和Git教程>还觉得不错,继续写了<为了Github默默付出,我想了解你>,那么继续写Git 基础知识. Git 官网:https: ...

  4. react 入门与进阶教程

    react 入门与进阶教程 前端学习对于我们来说越来越不友好,特别是随着这几年的发展,入门门槛越来越高,连进阶道路都变成了一场马拉松.在学习过程中,我们面临很多选择,vue与react便是一个两难的选 ...

  5. 最适合新手入门的SpringCloud教程 6—Ribbon负载均衡「F版本」

    SpringCloud版本:Finchley.SR2 SpringBoot版本:2.0.3.RELEASE 源码地址:https://gitee.com/bingqilinpeishenme/Java ...

  6. 零基础快速入门SpringBoot2.0教程 (二)

    一.SpringBoot2.x使用Dev-tool热部署 简介:介绍什么是热部署,使用springboot结合dev-tool工具,快速加载启动应用 官方地址:https://docs.spring. ...

  7. 零基础快速入门SpringBoot2.0教程 (三)

    一.SpringBoot Starter讲解 简介:介绍什么是SpringBoot Starter和主要作用 1.官网地址:https://docs.spring.io/spring-boot/doc ...

  8. 零基础快速入门SpringBoot2.0教程 (四)

    一.JMS介绍和使用场景及基础编程模型 简介:讲解什么是小写队列,JMS的基础知识和使用场景 1.什么是JMS: Java消息服务(Java Message Service),Java平台中关于面向消 ...

  9. Highcharts入门+Highcharts基础教程,【非常值得学习的资料】

    http://www.hcharts.cn/docs/index.php?doc=index Highcharts入门章节目录 Highcharts简介 Highcharts下载与使用 Highcha ...

  10. mvc5入门,经典教程。。

    转子 http://www.yanjinnan.com/archives/category/tech/efmvc ASP.NET MVC 5  一 入门 发表于2013 年 8 月 12 日由颜晋南 ...

随机推荐

  1. 2023河南省ICPC大学生程序设计竞赛-wh

    第一次出去比赛,首先感谢程老师选择我们新生更多的比赛机会,感谢! 在周六我们一起做了高铁出发取洛阳参加icpc河南省赛,不得不说洛阳师范学院确实环境很好看..在热身赛时,已经被泼了冷水,这C也太难了, ...

  2. HTML超文本标记语言2

    二.基本标签 1.文件标签(结构) <html> 根标签 <head> <title>页面标题(标签)</title> </head> &l ...

  3. java读取txt文件解决乱码问题

    说明:由于txt文件有bom和不同的编码方式,导致导入数据时产生乱码,以下代码完美解决乱码问题. 参考他人代码,结合自己的业务加工完成,费了大半天功夫完成,希望对大家有点用处. 废话不多说,直接上代码 ...

  4. 交换分区swap的创建与管理

    前言 swap分区是linux系统中一块特殊的硬盘空间,当实际内存不够用的时候,系统会按照一定的算法将部分不用的数据放在swap分区中,从而为当前运行的程序腾出足够的内存空间.好处在于避免内存资源不足 ...

  5. Redhat 8.2 系统语言切换(英文转中文)

    前提条件 确保已连上网,并且配好 yum 源 若未配好 yum 源 可参考我上一篇文章 部分 Linux 换国内源 操作步骤 安装中文语言包 dnf install glibc-langpack-zh ...

  6. 部分 Linux 换国内源

    Centos 8 / Redhat 8 换国内源 操作步骤 先把原本的官方 yum 源 删除 或 备份 cd /etc/yum.repos.d/ 备份(Redhat 同理) rename repo r ...

  7. 【译】Silverlight 不会消亡 XAML for Blazor 到来

    Userware 正在使用早已消失的.令人怀念的微软 Silverlight Web 开发平台的遗留来支持其新的"XAML for Blazor"产品,该产品允许 .NET 开发人 ...

  8. Linux 内核音频子系统调试

    debugfs 文件系统 debugfs 可以为 Linux 内核各个模块的分析调试,提供许多信息,如音频子系统的 ASoC,以及 tracing 等.debugfs 文件系统可以通过命令行工具挂载, ...

  9. MindSponge分子动力学模拟——Constraint约束

    技术背景 在前面的几篇博客中,我们已经介绍了MindSponge的基本使用方法,比如定义一个分子系统.计算分子的单点能以及迭代器的使用等.有了这些基础的教程,用户以及可以执行一些比较简单的模拟任务,比 ...

  10. 6.swagger完善:界面显示注释+多版本控制

    周末,写点简单的水一下. 新版本的vs创建项目的时候可以选择自带一个swagger.然而这只是基本的swagger功能. 几个接口无所谓啦,随着接口越来越多,就这么丢给你,一时间也会懵逼,所以这篇文章 ...