快捷键

切换暗色模式 CtrlD
搜索 CtrlK
关闭弹窗 Esc
返回顶部 Ctrl
快捷键面板 Ctrl/
C++信息学奥赛打字闯关
首页 闯关训练 段位系统 题库中心
技术博客 新闻资讯
排行榜 信奥社区 成就殿堂 在线留言 AI助手
NOI 2025 大纲修订版

考前集训 · 一本通

基于 CCF 官方《NOI 大纲(2025年修订版)》精心编撰
覆盖 CSP-J(入门级)、CSP-S/NOIP(省一冲刺)、NOI(国家集训队)全部考点
从零基础到国家集训队,一本就通!

315+知识点
79知识区块
3难度等级
200+代码模板
向下滚动开始学习
Level 1-5 入门级 CSP-J 27个知识区块 · 约180个知识点
部分预览
Level 5-8 提高级 CSP-S 28个知识区块 · 含决策单调性/换根DP/差分约束
VIP专享
Level 7-10 NOI 级 24个知识区块 · 含点分治/最小割/PAM建模
VIP专享

入门级

CSP-J 认证 · Level 1-5

零基础到 CSP-J 一等奖。涵盖计算机基础、C++语法、基础数据结构、入门算法和数学基础。适合初学C++、目标CSP-J一等奖的选手。

Lv.1

1.1 计算机基础与编程环境

计算机基本构成(冯·诺依曼体系结构):

  • 运算器(ALU):负责算术运算(+、-、*、/)和逻辑运算(AND、OR、NOT)。
  • 控制器(CU):程序的"指挥官",从内存取指令→解释指令→发出控制信号。运算器+控制器=CPU
  • 存储器(Memory):内存(RAM,断电丢失)和外存(硬盘/SSD,持久化)。内存是性能瓶颈。
  • 输入/输出设备(I/O):键盘、鼠标、显示器、打印机等。

编译全过程:源代码(.cpp) → 预处理(#include展开、宏替换) → 编译(C++→汇编) → 汇编(汇编→目标文件.o) → 链接(合并目标文件+库→可执行文件)

数据单位体系:1Byte=8bit, 1KB=1024B, 1MB=1024KB, 1GB=1024MB。32位系统内存上限约4GB(2³²bytes)。

  • 竞赛编译:g++ -std=c++14 -O2 -Wall -o prog source.cpp(-std=c++14为CSP指定标准,-O2为二级优化)
  • NOI Linux环境:Windows能过不代表Linux能过,最终评测在NOI Linux下进行。
C++ 完整程序 可编译运行
// 竞赛标准程序模板(文件输入输出)
#include <bits/stdc++.h>
using namespace std;

int main() {
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    
    int a, b;
    cin >> a >> b;
    cout << a + b << endl;
    
    fclose(stdin); fclose(stdout);
    return 0;
}
考试技巧 & 注意事项
  • 初赛分值:计算机基础选择题约15-20分,务必熟记各部件功能
  • 内存计算:int占4字节,1000万int数组≈40MB——不能开太大
  • 复赛铁律:freopen是拿分前提,路径错误=0分,文件名大小写敏感
  • 竞赛中禁用:system("pause")、getch()等——评测机会卡死
Lv.2

1.2 C++基础语法与数据类型

C++程序结构要点:每个程序必须有且仅有一个main()函数。语句以分号结尾,代码块用花括号。

标识符规则:字母/数字/下划线,不能数字开头,区分大小写,不能使用C++关键字。

数据类型速查表:

类型关键字字节取值范围printf格式
整型int4-2³¹ ~ 2³¹-1(约±21亿)%d
长整型long long8-2⁶³ ~ 2⁶³-1(约±9×10¹⁸)%lld
无符号整型unsigned int40 ~ 2³²-1(约42亿)%u
单精度浮点float4约7位有效数字%f
双精度浮点double8约15位有效数字%lf
字符型char1-128~127(ASCII码)%c
布尔型bool1true(1)/false(0)%d

关键注意事项:

  • const常量:const int MAXN = 1e5 + 5; 编译期确定,优于#define宏(有类型检查)。
  • 全局变量自动初始化为0,局部变量是随机值——务必手动初始化!
  • 溢出防范:两个int相乘结果还是int,可能溢出!用 1LL * a * b 强制转long long。
  • 输入输出:关闭同步后cin/cout速度媲美scanf/printf,但不能混用
C++ 完整程序 可编译运行
#include <bits/stdc++.h>
using namespace std;

int main() {
    int a = 42;
    long long b = 1e18;      // 10^18
    double pi = 3.14159265358979;
    char ch = 'A';
    bool flag = true;
    
    int x, y; cin >> x >> y;
    cout << x + y << endl;
    printf("%d + %d = %d\n", x, y, x+y);
    printf("pi = %.10f\n", pi);
    
    // 快速IO(大数据量时使用)
    ios::sync_with_stdio(false);
    cin.tie(0);
    return 0;
}
考试技巧 & 注意事项
  • 初赛常考类型范围:int约21亿,超出用long long
  • 复赛中建议使用scanf/printf或关闭同步的cin/cout
  • 万能头文件仅在竞赛环境可用
Lv.2

1.3 基本语句与流程控制

三大流程结构——所有算法的基础:

  • 顺序结构:代码从上到下逐行执行,看似简单但变量定义顺序、初始化时机都影响程序正确性。

分支结构详解:

  • if-else链:最常用。注意 else 与最近的未配对 if 匹配(悬挂else问题)。
  • switch:仅支持整型/字符型,每个case末尾必须加break,否则会"穿透"。
  • 三目运算符:max = (a > b) ? a : b; 简洁但嵌套不超过2层。

循环结构对比与选择:

  • for:已知确切循环次数的首选。三段式:初始化→条件→增量。
  • while:先判断后执行,适合不确定次数但知道终止条件的场景。
  • break跳出当前循环,continue跳过本次迭代剩余部分。

时间复杂度快速估算(竞赛关键!):C++约1秒执行10⁸次基础运算。10⁶→安全,10⁷→勉强,10⁸→危险(可能TLE)。嵌套循环每层乘10倍。

C++ 完整程序 可编译运行
// 完整程序:分支结构与循环综合演示
#include <bits/stdc++.h>
using namespace std;

int main() {
    // ===== 分支结构 =====
    int score;
    cin >> score;
    if (score >= 90)      cout << "A" << endl;
    else if (score >= 80) cout << "B" << endl;
    else if (score >= 70) cout << "C" << endl;
    else if (score >= 60) cout << "D" << endl;
    else                  cout << "F" << endl;
    
    // ===== for循环:高斯求和 =====
    int n = 100, sum = 0;
    for (int i = 1; i <= n; i++) sum += i;
    cout << "1+2+...+100 = " << sum << endl;  // 5050
    
    // ===== while循环:数字反转 =====
    int num = 12345, rev = 0;
    while (num > 0) {
        rev = rev * 10 + num % 10;
        num /= 10;
    }
    cout << "reversed: " << rev << endl;  // 54321
    
    // ===== 嵌套循环:九九乘法表 =====
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= i; j++)
            printf("%d*%d=%-2d ", j, i, i * j);
        cout << endl;
    }
    // ===== 三目运算符 =====
    int maxVal = (sum > rev) ? sum : rev;
    cout << "max = " << maxVal << endl;
    return 0;
}
考试技巧 & 注意事项
  • 循环边界注意 off-by-one 错误(多1或少1)
  • switch 中的 break 容易遗漏,导致"穿透"现象
  • 嵌套循环注意时间复杂度:O(n²) 在 n=10⁴ 时达到 10⁸,可能超时
Lv.3

1.4 运算符与位运算

运算符优先级(从高到低,初赛必考!):一元(++ -- ! ~) → 乘除取模 → 加减 → 移位(<< >>) → 关系比较(< <= > >=) → 相等(== !=) → 按位与(&) → 按位异或(^) → 按位或(|) → 逻辑与(&&) → 逻辑或(||) → 赋值(=)

常见优先级陷阱:

  • if (a & 1 == 0) 实际是 a & (1 == 0),必须写成 if ((a & 1) == 0)
  • 短路求值:&&左边false→不执行右边;||左边true→不执行右边。利用它避免除零:if (b != 0 && a / b > 10)

位运算速查(高频考点):

运算符含义示例口诀
&按位与(全1才1)5&3=1 (101&011=001)有0则0
|按位或(有1则1)5|3=7 (101|011=111)有1则1
^按位异或(不同为1)5^3=6 (101^011=110)相同0不同1
~按位取反~5=-60变1,1变0
<<左移(×2ⁿ)1<<n=2ⁿ每左移1位×2
>>右移(÷2ⁿ)8>>2=2每右移1位÷2

10个必背位运算技巧:判断奇偶(x&1)、获取第k位、置1/置0、消去最低位1(x&(x-1))、lowbit(x&-x)、交换两数(异或)、判断2的幂。

C++ 完整程序 可编译运行
// 完整程序:位运算十大必背技巧
#include <bits/stdc++.h>
using namespace std;

int main() {
    int x = 10;  // 二进制: 1010
    
    // 1. 判断奇偶
    cout << (x & 1 ? "odd" : "even") << endl;  // even
    // 2. 获取第k位(从0开始)
    int k = 3;
    cout << "bit " << k << ": " << ((x >> k) & 1) << endl; // 1
    // 3. 将第k位设为1
    cout << "set bit: " << (x | (1 << k)) << endl;        // 18
    // 4. 消去最低位的1
    cout << "pop lowest 1: " << (x & (x - 1)) << endl;    // 8
    // 5. lowbit: x & -x
    cout << "lowbit: " << (x & -x) << endl;               // 2
    // 6. 交换两数(异或,不用临时变量)
    int a = 5, b = 7;
    a ^= b; b ^= a; a ^= b;
    cout << "swap: a=" << a << ", b=" << b << endl;       // a=7, b=5
    // 7. 判断是否为2的幂
    bool isPow2 = (x > 0) && ((x & (x - 1)) == 0);
    cout << "is power of 2: " << (isPow2 ? "yes" : "no") << endl;
    // 8. 统计二进制中1的个数
    int cnt = 0, tmp = 15;  // 1111
    while (tmp) { tmp &= (tmp - 1); cnt++; }
    cout << "popcount(15) = " << cnt << endl;  // 4
    // 9. 翻转第k位
    cout << "flip bit 0: " << (x ^ (1 << 0)) << endl;  // 11
    // 10. 枚举子集
    int mask = 0b1101;  // 13
    cout << "subsets: ";
    for (int sub = mask; sub; sub = (sub - 1) & mask)
        cout << sub << " ";
    cout << endl;
    return 0;
}
考试技巧 & 注意事项
  • 位运算是CSP-J初赛必考,需熟练掌握
  • & | ^ 优先级低于 ==,写条件时必须加括号!
  • 取模结果符号与a相同:-5%3=-2(C++规则,不是Python的1)
  • lowbit(x) = x & -x,树状数组/状压DP的基础
Lv.3

1.5 数学库函数

cmath常用函数速查:

函数含义示例
abs(x)整数绝对值abs(-5)=5
fabs(x)浮点绝对值fabs(-3.14)=3.14
round(x)四舍五入round(3.5)=4
floor(x)向下取整floor(3.8)=3
ceil(x)向上取整ceil(3.1)=4
sqrt(x)平方根sqrt(16)=4
pow(a,b)a的b次方pow(2,10)=1024
log/log2/log10对数log2(8)=3
sin/cos/tan三角函数(弧度制)sin(π/2)≈1
exp(x)e的x次方exp(2)≈7.389

重要技巧:(int)(log10(n))+1求整数n的位数。acos(-1.0)获取高精度π。

C++ 完整程序 可编译运行
// 完整程序:数学库函数演示
#include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-9;

int main() {
    double x = -3.7;
    cout << fixed << setprecision(4);
    cout << "floor(" << x << ") = " << floor(x) << endl;   // -4.0000
    cout << "ceil(" << x << ") = " << ceil(x) << endl;     // -3.0000
    cout << "round(" << x << ") = " << round(x) << endl;   // -4.0000
    
    cout << "sqrt(2) = " << sqrt(2) << endl;               // 1.4142
    cout << "log2(1024) = " << log2(1024) << endl;          // 10
    
    // 高精度π
    const double PI = acos(-1.0);
    cout << "PI = " << setprecision(10) << PI << endl;
    
    // 浮点数比较(不能用==!)
    double a = 0.1 + 0.2, b = 0.3;
    if (fabs(a - b) < EPS)
        cout << "0.1+0.2 == 0.3 (within eps)" << endl;
    else
        cout << "WARNING: float precision error!" << endl;
    
    // 求整数位数
    int n = 12345;
    cout << "digits: " << (int)log10(n) + 1 << endl;  // 5
    
    return 0;
}
考试技巧 & 注意事项
  • floor(-3.7) = -4.0(向负无穷取整),与整数除法 int(-3.7)=-3 不同!
  • pow 返回 double,大整数幂用快速幂避免精度问题
  • 浮点数比较用 fabs(a-b) < 1e-9,绝不能用 ==!
  • acos(-1.0) 获取高精度 π,(int)log10(n)+1 求整数位数
Lv.3

1.6 数组与vector

数组核心知识:

  • 一维数组:int arr[100];下标0~99。越界是未定义行为,导致RE或WA。
  • 二维/多维:int mat[100][100];先行后列。memset(a,0,sizeof(a))清零(只适用于0或-1)。
  • 全局 vs 局部:全局数组默认初始化为0,局部数组是随机值(务必初始化)。大数组开在全局区避免爆栈。
  • vector动态数组:vector v(n);,push_back/pop_back/size/clear。
  • C++11范围for:for (int x : arr) cout << x;
C++ 完整程序 可编译运行
// 完整程序:数组与 vector 使用演示
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int globalArr[N]; // 全局数组自动初始化为0

int main() {
    // ===== 基本数组操作 =====
    int arr[10] = {1, 2, 3};  // 其余为0
    cout << "arr[0]=" << arr[0] << " arr[9]=" << arr[9] << endl;
    
    // 二维数组
    int mat[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    cout << "mat[1][2] = " << mat[1][2] << endl;  // 6
    
    // memset 清零 (仅 0 或 -1)
    int memo[100];
    memset(memo, -1, sizeof(memo));
    cout << "memo[0] = " << memo[0] << endl;  // -1
    
    // fill 设置任意值
    fill(memo, memo + 100, 42);
    cout << "filled: " << memo[0] << endl;  // 42
    
    // ===== vector 动态数组 =====
    vector<int> v = {1, 2, 3};
    v.push_back(4); v.pop_back();
    sort(v.begin(), v.end());
    cout << "vector: ";
    for (int x : v) cout << x << " ";  // 1 2 3
    cout << endl;
    
    // reverse
    reverse(v.begin(), v.end());
    cout << "reversed: ";
    for (int x : v) cout << x << " ";  // 3 2 1
    cout << endl;
    
    // 去重
    vector<int> v2 = {3,1,4,1,5};
    sort(v2.begin(), v2.end());
    v2.erase(unique(v2.begin(), v2.end()), v2.end());
    cout << "unique: ";
    for (int x : v2) cout << x << " ";  // 1 3 4 5
    cout << endl;
    
    return 0;
}
考试技巧 & 注意事项
  • 大数组必须开在全局区(main外面),否则栈溢出!局部数组上限约 10⁵
  • memset 按字节设值,设1得到 0x01010101 不是 1!用 fill 代替
  • int数组:10⁷个元素≈40MB,一般 256MB 限制下安全上限约 5×10⁷
Lv.3

1.7 字符串处理

字符串处理要点:

  • C风格字符串:char s[100];'\0'结尾。strlen/strcpy/strcat/strcmp。
  • C++ string类(推荐):s.length()、s.substr(pos,len)、s.find(t)返回位置或npos、s.insert/erase、s+t拼接、getline(cin,s)读整行。
  • 字符判断(cctype):isdigit/isalpha/islower/isupper/tolower/toupper。
  • 字符串与数字互转:stoi(s)字符串→整数、to_string(n)整数→字符串。
C++ 完整程序 可编译运行
// 完整程序:字符串操作全解
#include <bits/stdc++.h>
using namespace std;

int main() {
    string s = "Hello World";
    cout << "length: " << s.length() << endl;         // 11
    cout << "substr(0,5): " << s.substr(0, 5) << endl; // "Hello"
    cout << "find Wo: " << (int)s.find("Wo") << endl;  // 6
    cout << "find xyz: " << (int)s.find("xyz") << endl; // -1 (npos)
    
    // 遍历转换大小写
    string mixed = "HeLLo123";
    for (char& c : mixed) {
        if (isupper(c)) c = tolower(c);
        else if (islower(c)) c = toupper(c);
    }
    cout << "swapped: " << mixed << endl;  // hEllO123
    
    // 数字与字符串互转
    string numStr = "12345";
    int num = stoi(numStr);
    cout << "stoi+1: " << num + 1 << endl;                // 12346
    cout << "to_string: " << to_string(num + 1) << endl;   // "12346"
    
    // 判断回文
    string s2 = "racecar";
    string rev = s2;
    reverse(rev.begin(), rev.end());
    cout << s2 << " is palindrome: " << (s2 == rev ? "YES" : "NO") << endl;
    
    // 统计字符频率
    int cnt[26] = {0};
    for (char c : s)
        if (isalpha(c)) cnt[tolower(c) - 'a']++;
    
    // C风格字符串
    char cstr[100] = "hello";
    strcat(cstr, " world");
    cout << "C style: " << cstr << " (len=" << strlen(cstr) << ")" << endl;
    
    return 0;
}
考试技巧 & 注意事项
  • cin>> 跳过空白字符(空格/Tab/换行),读整行用 getline
  • strcmp 返回 0 表示相等(不是 bool!),正/负表示字典序
  • string 的 find 返回 string::npos(大无符号数)表示未找到
  • string::npos 是一个很大的无符号数,不要用 > 0 判断
Lv.4

1.8 函数与递归

函数:返回类型 函数名(参数列表) { 函数体 }。传值(不改变原变量) vs 传引用(可修改原变量,用&)。

递归三要素:

  1. 边界条件(终止条件)——最先判断
  2. 递归关系(递推公式)——大问题化小问题
  3. 递归调用——参数朝向边界收敛

经典递归问题:阶乘 factorial(n)=n*factorial(n-1)、斐波那契 fib(n)=fib(n-1)+fib(n-2)、汉诺塔、全排列。

时间复杂度分析:递推式T(n)=aT(n/b)+O(nᵈ),由Master Theorem决定。

C++ 完整程序 可编译运行
// 完整程序:函数、递归与记忆化搜索
#include <bits/stdc++.h>
using namespace std;

// 传引用:直接修改原变量
void swap_ref(int& a, int& b) { int t = a; a = b; b = t; }

// 阶乘(递归)
long long factorial(int n) {
    if (n <= 1) return 1;  // 边界条件
    return n * factorial(n - 1);
}

// 记忆化搜索:斐波那契 O(n)
long long memo[100] = {0};
long long fib(int n) {
    if (n <= 1) return n;
    if (memo[n]) return memo[n];
    return memo[n] = fib(n-1) + fib(n-2);
}

// 汉诺塔递归
int hanoiSteps = 0;
void hanoi(int n, char from, char to, char aux) {
    if (n == 1) {
        printf("%c -> %c\n", from, to); hanoiSteps++; return;
    }
    hanoi(n-1, from, aux, to);
    printf("%c -> %c\n", from, to); hanoiSteps++;
    hanoi(n-1, aux, to, from);
}

int main() {
    int a = 10, b = 20;
    swap_ref(a, b);
    cout << "swap: a=" << a << ", b=" << b << endl;  // a=20, b=10
    
    cout << "5! = " << factorial(5) << endl;         // 120
    cout << "fib(40) = " << fib(40) << endl;          // 102334155
    
    cout << "Hanoi(3):" << endl;
    hanoi(3, 'A', 'C', 'B');
    cout << "steps: " << hanoiSteps << endl;          // 7
    
    // 全排列
    vector<int> v = {1, 2, 3};
    cout << "Permutations: ";
    do {
        for (int x : v) cout << x;
        cout << " ";
    } while (next_permutation(v.begin(), v.end()));
    cout << endl;
    return 0;
}
考试技巧 & 注意事项
  • 递归必须有终止条件,否则栈溢出(SO)!
  • 深度递归 n>10⁵ 可能爆栈,改用迭代/手动栈
  • 朴素fib(40)约2⁴⁰≈10¹²次递归,记忆化后仅O(n)
  • 传引用(int&)避免大对象拷贝,且可修改原值
Lv.4

1.9 结构体与指针

结构体(struct):

  • struct Student { string name; int score; }; 将多种类型聚合。
  • 排序:配合sort自定义cmp或重载operator <。
  • 联合体(union):所有成员共享内存,大小为最大成员的大小。初赛偶有涉及。

指针基础:

  • int* p = &a;定义指针;*p解引用;&a取地址;p++指向下一元素。
  • 引用(&):变量的别名,定义时必须初始化。2025大纲新增了"引用"考点。
  • void swap(int& a, int& b) { int t=a; a=b; b=t; } 引用传参可直接修改原变量。
C++ 完整程序 可编译运行
// 完整程序:结构体、排序与引用
#include <bits/stdc++.h>
using namespace std;

struct Student {
    string name;
    int chinese, math, english;
    int total() const { return chinese+math+english; }
    bool operator < (const Student& o) const {
        if (total() != o.total()) return total() > o.total();
        return name < o.name;
    }
};

int main() {
    vector<Student> stu = {
        {"Alice",90,88,95},
        {"Bob",85,92,87},
        {"Carol",92,90,93},
        {"David",85,92,87}
    };
    sort(stu.begin(), stu.end());
    cout << "Ranking:" << endl;
    for (auto& s : stu)
        printf("  %s: %d (C:%d M:%d E:%d)\n",
               s.name.c_str(), s.total(), s.chinese, s.math, s.english);
    
    // 引用传参
    auto addOne = [](int& x) { x++; };
    int a = 10; addOne(a);
    cout << "addOne: " << a << endl;  // 11
    
    // 指针基础
    int* p = &a;
    cout << "*p = " << *p << endl;  // 11
    *p = 20;
    cout << "a = " << a << endl;    // 20
    
    return 0;
}
考试技巧 & 注意事项
  • 引用必须在定义时初始化,不能改变绑定
  • 结构体排序是高频考点,掌握两种方式
  • 指针在竞赛中较少使用,但初赛选择题涉及
Lv.4

1.10 STL模板库入门

STL核心容器全方位对比——C++竞赛最大优势:

容器底层结构插入/删除查找适合场景
vector动态数组O(1)尾/O(n)中O(n)常用顺序存储
stackdequeO(1)栈顶-后进先出(LIFO)
queuedequeO(1)队首尾-先进先出(BFS)
priority_queue二叉堆O(log n)O(1)取最值动态最值
set/multiset红黑树O(log n)O(log n)有序+自动去重
map红黑树O(log n)[key]O(log n)键值映射
unordered_map哈希表O(1)均摊O(1)均摊快速查找(注意被卡)

algorithm常用函数:sort(O(n log n))、reverse、lower_bound/upper_bound(O(log n),要求有序!)、unique(去重,需先排序)、next_permutation(全排列枚举神器)、min_element/max_element。

C++ 完整程序 可编译运行
// 完整程序:STL 容器与算法综合演示
#include <bits/stdc++.h>
using namespace std;

int main() {
    // ===== vector 排序去重 =====
    vector<int> v = {3,1,4,1,5,9,2,6};
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(),v.end()), v.end());
    cout << "unique: ";
    for (int x : v) cout << x << " ";
    cout << endl;  // 1 2 3 4 5 6 9
    
    // ===== stack 括号匹配 =====
    string s = "(()())";
    stack<char> stk;
    bool ok = true;
    for (char c : s) {
        if (c == '(') stk.push(c);
        else if (!stk.empty()) stk.pop();
        else { ok = false; break; }
    }
    cout << (ok && stk.empty() ? "OK" : "FAIL") << endl;
    
    // ===== priority_queue 小顶堆 =====
    priority_queue<int, vector<int>, greater<int>> pq;
    for (int x : {3,1,4,1,5}) pq.push(x);
    cout << "min-heap: ";
    while (!pq.empty()) { cout << pq.top(); pq.pop(); }
    cout << endl;  // 1 1 3 4 5
    
    // ===== map 词频统计 =====
    map<string, int> freq;
    for (auto w : {"apple","banana","apple"}) freq[w]++;
    for (auto& [k,v] : freq) cout << k << ":" << v << " ";
    cout << endl;
    
    // ===== lower_bound =====
    auto it = lower_bound(v.begin(), v.end(), 5);
    cout << "first>=5: " << *it << " at idx " << it-v.begin() << endl;
    return 0;
}
考试技巧 & 注意事项
  • STL容器简化代码,CSP-J/S均允许
  • set/map基于红黑树O(log n),unordered_map哈希O(1)
  • priority_queue默认大顶堆,小顶堆需额外声明
  • sort内部使用Introsort算法,O(n log n)
Lv.3

2.1 线性结构:链表/栈/队列

三大基础线性结构:

  • 链表:单链表(指向后继)、双向链表(前驱+后继)、循环链表。插入/删除O(1),随机访问O(n)。
  • 栈(Stack):LIFO。应用:括号匹配、表达式求值、DFS非递归、撤销操作。
  • 队列(Queue):FIFO。应用:BFS、任务调度、消息队列。
  • 数组模拟:竞赛中常用数组模拟栈/队列,比STL更快。
C++ 完整程序 可编译运行
// 完整程序:线性结构综合演示
#include <bits/stdc++.h>
using namespace std;

int main() {
    // ===== 数组模拟栈 =====
    const int MAX = 1000;
    int stk[MAX], top = 0;
    stk[++top] = 10; stk[++top] = 20; stk[++top] = 30;
    cout << "stack pop: ";
    while (top > 0) cout << stk[top--] << " ";
    cout << endl;  // 30 20 10
    
    // ===== 数组模拟队列 =====
    int q[MAX], head = 0, tail = -1;
    q[++tail] = 1; q[++tail] = 2; q[++tail] = 3;
    cout << "queue pop: ";
    while (head <= tail) cout << q[head++] << " ";
    cout << endl;  // 1 2 3
    
    // ===== 链表实现(头插法)=====
    struct Node {
        int val; Node* next;
        Node(int v) : val(v), next(nullptr) {}
    };
    Node* headNode = nullptr;
    for (int i = 1; i <= 3; i++) {
        Node* n = new Node(i);
        n->next = headNode; headNode = n;
    }
    cout << "linked list: ";
    for (Node* p = headNode; p; p = p->next)
        cout << p->val << " -> ";
    cout << "null" << endl;  // 3 -> 2 -> 1 -> null
    
    while (headNode) { Node* t = headNode; headNode = headNode->next; delete t; }
    return 0;
}
考试技巧 & 注意事项
  • 数组模拟栈/队列比STL更快,性能敏感时使用
  • 单调栈/单调队列是CSP-S高频考点,入门级只需概念
  • 理解top指针的初始值及其意义
Lv.4

2.2 树的定义与二叉树

树的基本术语:根(Root)—唯一没有父节点的节点 / 父/子/兄弟节点 / 度(Degree)—子节点数 / 叶子(Leaf)—度=0 / 深度—从根到该节点的路径长度 / 高度—到最远叶子的路径长度。

二叉树核心性质(初赛计算题常客):

  1. 第k层最多 2^(k-1) 个节点(k≥1)
  2. 深度为h的二叉树最多 2^h-1 个节点
  3. n₀ = n₂ + 1:叶子数 = 度为2的节点数 + 1(由边数等式 n-1 = n₁ + 2n₂ 推出)
  4. n个节点的完全二叉树深度 = ⌊log₂n⌋ + 1

存储方式:链式(struct Node* left,right)灵活通用;数组(根下标1,i左子2i,i右子2i+1,i父⌊i/2⌋)适合完全二叉树。

四种遍历对比:前序(根-左-右)、中序(左-根-右→BST得到有序序列)、后序(左-右-根→删树用)、层序(BFS,队列实现)。已知前序+中序 或 后序+中序 可唯一确定二叉树(必须有中序!仅前序+后序不能唯一确定)。

C++ 完整程序 可编译运行
// 完整程序:二叉树定义与四种遍历
#include <bits/stdc++.h>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left, *right;
    TreeNode(int v) : val(v), left(nullptr), right(nullptr) {}
};

// 前序遍历:根-左-右
void preorder(TreeNode* root) {
    if (!root) return;
    cout << root->val << " ";
    preorder(root->left);
    preorder(root->right);
}

// 中序遍历:左-根-右
void inorder(TreeNode* root) {
    if (!root) return;
    inorder(root->left);
    cout << root->val << " ";
    inorder(root->right);
}

// 后序遍历:左-右-根
void postorder(TreeNode* root) {
    if (!root) return;
    postorder(root->left);
    postorder(root->right);
    cout << root->val << " ";
}

// 层序遍历(BFS)
void levelorder(TreeNode* root) {
    if (!root) return;
    queue<TreeNode*> q; q.push(root);
    while (!q.empty()) {
        TreeNode* cur = q.front(); q.pop();
        cout << cur->val << " ";
        if (cur->left)  q.push(cur->left);
        if (cur->right) q.push(cur->right);
    }
}

int main() {
    // 手动构建一棵二叉树
    //       1
    //      / \
    //     2   3
    //    / \   \
    //   4   5   6
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);
    root->right->right = new TreeNode(6);
    
    cout << "Preorder:  "; preorder(root); cout << endl;   // 1 2 4 5 3 6
    cout << "Inorder:   "; inorder(root); cout << endl;    // 4 2 5 1 3 6
    cout << "Postorder: "; postorder(root); cout << endl;  // 4 5 2 6 3 1
    cout << "Levelorder:"; levelorder(root); cout << endl;  // 1 2 3 4 5 6
    
    // 完全二叉树数组存储示例
    // root=1, i的左子=2i, i的右子=2i+1, i的父=i/2
    int tree[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    cout << "Array tree: node1=" << tree[1]
         << " left=" << tree[2] << " right=" << tree[3] << endl;
    return 0;
}
考试技巧 & 注意事项
  • 二叉树遍历是初赛选择题高频考点
  • 已知两种遍历序列重建二叉树,初赛几乎必考
  • 完全二叉树用数组存储最方便
Lv.4

2.3 完全二叉树与哈夫曼树

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

2.4 二叉搜索树(BST)

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

2.5 图的基础概念与存储

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.2

3.1 枚举法与模拟法

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.3

3.2 贪心法

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

3.3 递推与二分法

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

3.4 前缀和与差分(2025新增)

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

3.5 高精度计算

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

3.6 排序算法

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.5

3.7 搜索算法:DFS与BFS

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.5

3.8 图论基础:遍历与Flood Fill

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.5

3.9 动态规划基础

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.2

4.1 进制与进制转换

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

4.2 初等数论基础(含模运算与取余)

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP
Lv.4

4.3 排列组合基础

此内容需要 VIP 会员

开通VIP会员即可解锁本节及后续全部内容

立即开通 VIP

入门级预览结束

您已预览入门级的前 12 个知识区块。
登录后可查看全部入门级内容,开通 VIP 可解锁全部三个等级。

解锁全部学习集训内容

提高级(省一冲刺)+ NOI级(国家集训队)共 52 个高级知识区块,
覆盖 CSP-S 一等奖到 NOI 金牌的全部核心考点!

在线

给管理员留言

每条留言老师都会认真阅读并回复

📚 课程咨询 🔧 技术求助 💡 建议反馈 🤝 合作联系

留言发送成功!

您的留言已送达管理员后台

追踪码(请保存以便查询回复)
------