课程 · C++ 速查 · 零碎但天天用的那几样

零碎但天天用的那几样 例题与练习

这一组没有一样是算法,全是写代码的手势 —— 练一遍就不会再在读别人代码时卡住。

2 道例题3 道练习5 份可运行代码回速查看这一组的 8 条 →
怎么用这一页

例题给全套:题面、样例、参考代码、以及一步步的讲解。先自己读题想一遍, 再看代码,最后对着讲解核一遍自己想的对不对。

练习只给题面、样例和一句提示,答案是折叠起来的 —— 请先自己写一版跑通了再展开。写不出来也别直接看答案,先回速查那一组找找。

每份代码都能直接点运行:输入框里已经填好了样例输入, 把它改一改再跑,是这一页最值钱的用法。

先把地基摆一遍

1 段

这一组里没有一样是「算法」,全是写代码的手势。每一条都只要看一眼就会,但没人告诉你的话,读别人的代码时就会卡在那儿。

例题(2 道)

每道都给全套:题面 → 样例 → 参考代码 → 一步步的讲解。

例题 ① 温度记录

miscEx1.cpp

n 天的气温(可能是负数),请输出三个数:最高气温、最低气温、以及相邻两天温差绝对值的最大值。

然后再输出一行 n 个字符:第 i 个字符在第 i 天气温 ≥ 0 时是 +,否则是 -

输入格式第一行一个整数 n1 ≤ n ≤ 10⁵);第二行 n 个整数 tᵢ|tᵢ| ≤ 10⁴)。
输出格式第一行三个整数,用空格隔开;第二行 n 个字符,中间不要有空格。

输入

5
-3 0 7 2 -8

输出

7 -8 10
-+++-
最高 7、最低 −8;相邻四对的温差是 3、7、5、10 ⇒ 最大 10。第二行:−3 是负、0 是非负、7 正、2 正、−8 负 ⇒ -+++-
先想一想

一口气用上四样:maxminabs、三目。⚠ 只有一个地方要小心:n = 1 时「相邻两天」一对都没有。

miscEx1.cpp参考代码
// 例题 ①「温度记录」—— 零碎但天天用的那几样
//
// 一口气用上四样:max / min / abs / 三目。
// 它们单独讲都不值一节,可本书每一份代码里都有它们。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> t(n);
for (int i = 0; i < n; i++) cin >> t[i];
int hi = t[0], lo = t[0], gap = 0;
for (int i = 0; i < n; i++) {
hi = max(hi, t[i]); // ⚠ max 的两个参数类型必须一样
lo = min(lo, t[i]);
if (i > 0) gap = max(gap, abs(t[i] - t[i - 1])); // abs:绝对值
}
cout << hi << ' ' << lo << ' ' << gap << "\n";
// 三目运算符:一行的 if-else,而且它是一个**有值的表达式**,
// 所以能直接写在 cout << 里 —— ⚠ 但一定要加括号,它的优先级很低。
for (int i = 0; i < n; i++) cout << (t[i] >= 0 ? '+' : '-');
cout << "\n";
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
这段代码是怎么想出来的
  1. max(a, b) / min(a, b) 只收两个参数;三个以上要加一对花括号:max({a, b, c})
  2. ⚠ 它们最常撞的编译错误是两个参数类型必须完全一样max(1, 2LL) 编译不过,要写 max(1LL, 2LL) 或者 max<long long>(1, 2)
  3. abs(x) 是绝对值。整数用 abs,浮点数写 fabs 更清楚。
  4. 三目运算符 cond ? a : b 读成「如果 cond 成立就取 a,否则取 b」。它是一个有值的表达式 ⇒ 可以直接写在 cout << 里、写在 return 后面。
  5. ⚠ 而写进 cout <<必须加括号cout << (t >= 0 ? '+' : '-')。它的优先级很低,不加括号要么编译报错,要么结果不对。
  6. n = 1 的处理:让温差的初值是 0,并且只在 i > 0 时才去算差 ——这样一对都没有时答案自然是 0。
记住这一句

这四样单独讲都不值一节,可它们在本书每一份代码里都出现。

用到的写法:max(a, b) min(a, b) abs(x) cond ? a : b

例题 ② 把最大的那个换到最前面

miscEx2.cpp

n 个整数,找出其中最大的那个(如果有多个并列,取下标最小的那个),把它和第一个数交换位置,然后输出整个数组。

输入格式第一行一个整数 n1 ≤ n ≤ 10⁶);第二行 n 个整数。
输出格式一行 n 个整数,用空格隔开,行末不留空格。

输入

5
3 9 4 9 1

输出

9 3 4 9 1
两个 9 并列 ⇒ 取下标小的那个(第 2 个数),和第 1 个数换位置。
先想一想

注意 n 可以到 10⁶。⚠ 这个规模下,数组写在 main 里面会出事 —— 想想它放在哪儿。另外:找最大值时要记的是还是下标

miscEx2.cpp参考代码
// 例题 ②「把最大的那个换到最前面」—— 零碎但天天用的那几样
//
// 这一页是竞赛代码最常见的开头长什么样:
// 万能头 + using namespace std + const int N + 一个全局数组。
// ⚠ 数组开成**全局**的两个理由:它自动全是 0,而且不占栈(几十万个元素写在 main 里会爆栈)。
// ⚠ 那个多出来的 5 是留余量的:下标从 1 开始要多一格,加哨兵还要几格。
#include <bits/stdc++.h>
using namespace std;
const int N = 100005; // 题面写 n ≤ 100000,就写 100005
int a[N]; // 全局数组:程序启动时自动全填 0
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int best = 0; // 记下标,不是记值
for (int i = 1; i < n; i++)
if (a[i] > a[best]) best = i; // 用 > 而不是 >= ⇒ 并列时留住**下标最小**的那个
swap(a[0], a[best]); // 交换两个变量,不用自己写中间变量
for (int i = 0; i < n; i++) cout << a[i] << (i + 1 == n ? '\n' : ' ');
return 0;
}
点一下即可编辑
输入(stdin)
输出
点「运行 ▶」看结果
这段代码是怎么想出来的
  1. 竞赛代码最常见的开头就长这样:万能头 #include <bits/stdc++.h>using namespace std;const int N = 1000005;、然后一个全局数组 int a[N];
  2. ⚠ 数组开成全局的两个理由:① 它自动全是 0;② 它不占栈 —— 写在 main 里的数组放在栈上(一般只有 8 MB),10⁶ 个 int 就是 4 MB,再多一点就直接段错误。
  3. ⚠ 那个多出来的 5 是留余量的:下标从 1 开始要多一格,加哨兵还要几格。题面写 n ≤ 1000000,就写 1000005 —— 不差这几个字节。
  4. 找最大值时记下标而不是记值:因为待会儿要交换位置,光有值没用。⚠ 而判断写 a[i] > a[best](不是 >=)⇒ 并列时留住的是先出现的那个。
  5. swap(a[0], a[best]) 一句就换完了,不用自己写中间变量。它对 vector、string 这些也管用,而且是 O(1) 的(只换内部指针,不真的搬数据)。
记住这一句

> 还是 >=」这半个字符决定了并列时留谁 —— 而题面往往就在这半个字符上做文章。

用到的写法:const int N = 100005; swap(a, b) #include <bits/stdc++.h> using namespace std;

练习(3 道)

答案折叠着,先自己写一版。

练习 ① 三个数的最大值和最小值

miscTry1.cpp

给三个整数,输出其中最大的和最小的。

输入格式一行三个整数(|a| ≤ 10¹⁸)。
输出格式一行两个整数:最大值、最小值。

输入

3 9 -4

输出

9 -4
3 9 -4 里最大 9、最小 −4。
提示

max 只收两个参数 —— 三个数怎么办?(速查里那一条的最后半句。)⚠ 还有:注意数据范围。

miscTry1.cpp参考答案

用到的写法:max(a, b) min(a, b)

练习 ② 首尾对称交换

miscTry2.cpp

n 个整数,把第 1 个和第 n 个交换、第 2 个和第 n−1 个交换……然后输出。(也就是把整个数组倒过来,但请手写这个交换过程,别直接调 reverse。)

输入格式第一行一个整数 n1 ≤ n ≤ 10⁵);第二行 n 个整数。
输出格式一行 n 个整数,用空格隔开,行末不留空格。

输入

5
1 2 3 4 5

输出

5 4 3 2 1
1 2 3 4 5 倒过来是 5 4 3 2 1
提示

⚠ 循环该走到哪儿停?走满全程会发生什么?(在纸上拿 4 个数走一遍就明白了 —— 这是最经典的一个「白忙」。)

miscTry2.cpp参考答案
记住这一句

走半程(i < n / 2)才对。n 是奇数时正中间那个不用动,而 n / 2 恰好把它跳过了。

用到的写法:swap(a, b)

练习 ③ 求最小值

miscTry3.cpp

n 个整数,输出其中最小的那个。

输入格式第一行一个整数 n1 ≤ n ≤ 10⁵);第二行 n 个整数(|aᵢ| ≤ 10⁹)。
输出格式一行一个整数。

输入

4
-3 -9 -1 -7

输出

-9
四个数全是负的 —— 初值写 0 的话就答错了。
提示

「不断取更小的那个」要先有一个初值。⚠ 数可能是负的 ⇒ 初值写 0 就错了。有一个现成的常量可以用。

miscTry3.cpp参考答案
记住这一句

⚠ 但如果后面要拿这个初值做加法(比如最短路里的 dist[u] + w),就不能用 INT_MAX —— INT_MAX + 1 当场溢出成负数,那时候要改用 0x3f3f3f3f(它自己加自己还不溢出)。

用到的写法:INT_MAX LLONG_MAX max(a, b) min(a, b)