Lesson 0001 · vector:你的第一个竞赛利器

① 程序设计基础 — 第 1 课

上节课:没有 —— 这是第一课。
这节课:先看一眼全景。整门课反复练的其实是同一件事:读到一堆数据 → 处理它们 → 按格式输出。今天只解决其中「存」的那一半:用什么装数据。答案就是 vector,后面的数组、string、排序题,都建在它上面。
三句话速览

1. 为什么是 vector?

在算法竞赛里,几乎每一道题都要存一堆数据 —— 分数、坐标、数列、矩阵。用 C 的原生数组 int a[1000],你得提前猜大小,还容易越界。C++ 的 vector 就是来解决这个问题的。

C 数组vector<int>
int a[100]; 大小写死vector<int> a; 大小自动增长
不知道存了多少个a.size() 随时知道
越界不报错,debug 噩梦a.at(i) 越界会报错(调试用)
不能直接赋值整个数组a = b; 直接拷贝
核心思路:竞赛中,vector 就是存数据的默认选择。不用提前知道 n 是多少,读到多少存多少。

2. 基本操作

记住这四个操作,就够开始做题了:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;           // 声明一个空的 vector

    v.push_back(42);         // 往末尾加一个元素
    v.push_back(7);
    v.push_back(100);

    cout << v.size() << endl;    // 输出:3
    cout << v[0] << endl;        // 输出:42 (下标访问)

    // 用范围 for 遍历
    for (int x : v) {
        cout << x << ' ';       // 输出:42 7 100
    }
    return 0;
}

3. 竞赛输入模版

蓝桥杯和 ACM 的题目通常格式是:先给你 n,再给你 n 个数。学会下面这个模式,它就是你的肌肉记忆:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;                    // 先读个数
    vector<int> a(n);             // 直接开 n 个位置
    for (int i = 0; i < n; i++) {
        cin >> a[i];             // 逐个读入
    }

    // 现在 a 里就有所有数据了,想怎么处理就怎么处理
    return 0;
}

还有一种写法,如果你不确定会有多少个数(读到读完为止):

vector<int> a;
int x;
while (cin >> x) {              // 读到 EOF 为止
    a.push_back(x);
}
注意:用 cin >> x 循环读取时,本地测试按 Ctrl+Z 再回车(Windows)来模拟 EOF。在 OJ 上判题机会自动结束输入,不用管。

4. 热身题:求 n 个数的和

输入:第一行一个整数 n,第二行 n 个整数。
输出:这 n 个数的和。

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];

    int sum = 0;
    for (int x : a) sum += x;    // 范围 for 求和
    cout << sum << endl;
    return 0;
}

5. 坑点清单

6. 小测

Q1:下面哪个操作能正确输出 vector 的元素个数?
Q2:vector<int> v(10); 之后,v.size() 是多少?

7. 动手练习

打开 洛谷 P1046 · 陶陶摘苹果,用刚学的 vector 解决它。

思路:读入 10 个苹果高度 → 存进 vector<int> → 读入陶陶伸手高度 → 遍历判断哪些苹果的高度不大于伸手高度加 30。

卡住时的自查顺序

  1. 样例答案对不对?先把 10 个高度和伸手高度都打印出来,确认读进来的数没问题。
  2. 循环的边界写对了吗?10 个苹果是 i = 0 到 i < 10,别写成 i <= 10。
  3. 条件方向对不对?题目要的是「够得着」,即高度 ≤ 伸手高度 + 30。
  4. 输出行不行?OJ 通常只认一个整数,别多打提示文字。

本课小结

下一课预告
0002 sort 与 string —— 数据存进去之后就要处理它:用 sort 一行排序、用 unique 加 erase 去重,再把 string 当成「字符版 vector」来用。本课那套「先读 n 再逐个读入」的输入模版,下一课会接着用。
这一课的代码都很短,建议每个都亲手敲一遍、跑一遍。哪一句还不明白 —— 比如「为什么 a(n) 里就已经有 0 了」「size() 和 capacity() 到底差在哪」「范围 for 能不能改元素」 —— 直接问,可以从更小的地方讲起。

Lesson 0001 · 2024 夏 · 预计用时 20 min

回到 Mission · 教学笔记 · 资源列表

在线 cppreference: std::vector · OI Wiki: vector · 洛谷 P1046