NOI
NOICode
首页功能博客关于我们

学习资源

  • 博客
  • 学习指南
  • 备考攻略
  • 竞赛资讯

产品功能

  • 功能介绍
  • 价格方案
  • 常见问题
  • 更新日志

关于我们

  • 关于 NOI-Code
  • 联系我们
  • 合作伙伴

法律条款

  • 用户协议
  • 隐私政策
  • 服务条款

关注公众号

NOI
NOI-Code

AI 驱动的智能编程学习平台

© 2026 北京舞码科技有限公司

京ICP备2026015861号-1|京公网安备11011302007898号
Built withNOI-Code
首页/博客/头文件与IO加速完全指南
2026年5月21日·5 分钟阅读·NOI-Code 教研组NOI编译器头文件IO

头文件与IO加速完全指南

NOI/OI C++ 头文件与输入输出加速完全指南


1. 头文件策略

1.1 万能头文件

#include <bits/stdc++.h>

这一行等价于包含所有标准库头文件(vector、string、algorithm、map、queue……),是竞赛中最常用的写法。

优点

  • 一行搞定,不用记哪个函数在哪个头文件
  • 绝不会因为漏写头文件而编译错误

缺点

  • 编译速度略慢(包含了大量未使用的头文件)
  • 仅 GCC 支持,MSVC / Clang 不支持(但 NOI 评测机是 GCC,可以放心用)
  • 生产项目中不应使用

结论:NOI/OI 竞赛中直接用 #include <bits/stdc++.h>,工程中按需引入。


1.2 常用头文件速查

如果你希望精确控制(或在非 GCC 环境调试),下表列出最常用的:

头文件包含内容
<iostream>cin / cout / cerr
<cstdio>scanf / printf / getchar
<algorithm>sort / max / min / lower_bound
<vector>vector
<string>string / getline
<map>map / multimap
<set>set / multiset
<queue>queue / priority_queue
<stack>stack
<deque>deque
<unordered_map>unordered_map
<unordered_set>unordered_set
<cmath>sqrt / pow / abs(浮点)
<cstring>memset / memcpy / strlen
<cassert>assert
<climits>INT_MAX / LLONG_MAX 等常量
<numeric>accumulate / gcd / lcm

2. 命名空间

using namespace std;

竞赛中几乎必写。避免每次都写 std::cout、std::vector。

注意:生产代码中 using namespace std 是不好的实践,会引起命名冲突,但竞赛中问题不大。


3. 输入输出加速

3.1 为什么 cin 默认很慢?

C++ 的 cin/cout 默认做了两件事:

  1. 与 C 的 stdio 同步:保证 cin 和 scanf 混用时输出顺序正确。这会导致 cin 每次操作都要刷新 C 缓冲区,大幅降速。
  2. cin 与 cout 绑定:每次读取 cin 前都先刷新 cout,保证提示文字先输出。这在交互式场景有用,竞赛中是纯开销。

3.2 两行加速代码

ios::sync_with_stdio(false);
cin.tie(nullptr);

必须放在所有 cin/cout 操作之前(通常是 main 函数的第一行)。


3.3 逐行解析

ios::sync_with_stdio(false)

ios::sync_with_stdio(false);
  • 作用:关闭 C++ 流(cin/cout)与 C 流(scanf/printf)的同步。
  • 效果:cin/cout 拥有独立缓冲区,读写速度接近 scanf/printf。
  • 代价:关闭后不能混用 cin 和 scanf(或 cout 和 printf),否则输出顺序不可预期。

cin.tie(nullptr)

cin.tie(nullptr);  // 等价于 cin.tie(NULL),推荐用 nullptr
  • 默认状态:cin 绑定到 cout,每次读取前自动 flush cout。
  • 作用:解除绑定,让 cout 不再在每次 cin 前强制刷新。
  • 效果:大量交替读写时速度显著提升。
  • 代价:交互题(要求"先输出提示再读取")中需要手动 cout << flush 或 cout << endl。

3.4 加速效果对比

在读取 10610^6106 个整数的场景下(参考值,实际因机器和数据而异):

写法相对速度
cin(默认,不加速)1x(最慢)
scanf~3–5x
cin + 两行加速~3–5x(与 scanf 相当)
手写快读(见下文)~8–10x

3.5 标准模板

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    for (int i = 0; i < n; ++i) {
        int x;
        cin >> x;
        cout << x << '\n';  // 用 '\n' 而不是 endl(见下方说明)
    }

    return 0;
}

4. '\n' vs endl

这是一个常见性能陷阱:

cout << '\n';   // ✅ 只输出换行符,不刷新缓冲区
cout << endl;   // ❌ 输出换行符 + 强制刷新缓冲区(flush)

endl 每次都刷新缓冲区,在输出量大时会严重拖慢速度。

规则:

  • 竞赛中一律用 '\n',不用 endl。
  • 仅在调试或交互题需要立即刷新时才用 endl 或 cout << flush。

5. 手写快读(极限优化)

当数据规模达到 10710^7107 级别,scanf 也可能超时时,使用手写快读:

// 快速读取整数(支持负数)
inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = x * 10 + (c - '0');
        c = getchar();
    }
    return x * f;
}

// 使用方式
int n = read();
int a = read();

快写(输出整数):

inline void write(int x) {
    if (x < 0) { putchar('-'); x = -x; }
    if (x > 9) write(x / 10);
    putchar('0' + x % 10);
}

// 使用方式
write(ans);
putchar('\n');

注意:手写快读使用 getchar(),不能与 cin 混用。与 scanf 也不建议混用。


6. 文件输入输出

竞赛中常见"文件 I/O"要求(如 NOIP 系列):

// 方法一:freopen(最常用)
freopen("input.txt", "r", stdin);   // 将标准输入重定向到文件
freopen("output.txt", "w", stdout); // 将标准输出重定向到文件

// 之后正常使用 cin/scanf/cout/printf 即可
// 方法二:fstream(不影响 cin/cout)
#include <fstream>
ifstream fin("input.txt");
ofstream fout("output.txt");

int x;
fin >> x;
fout << x << '\n';

竞赛惯例:使用 freopen 方法,更简洁,不需要改动读写代码。


7. 交互题特殊处理

交互题中禁止关闭同步,或者需要每次输出后立即刷新:

// 交互题模板
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 不要加 ios::sync_with_stdio(false)!
    // 或者加了之后,每次输出必须手动 flush

    cout << "? 5" << endl;   // endl 保证立即发送给裁判
    int ans;
    cin >> ans;

    cout << "! " << ans << endl;
    return 0;
}

8. 完整竞赛模板

#include <bits/stdc++.h>
using namespace std;

// 常用类型别名
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using vi = vector<int>;

// 常用常量
const int INF = 0x3f3f3f3f;          // 约 10^9,可用于初始化最大值
const long long LLINF = 0x3f3f3f3f3f3f3f3fLL;
const int MOD = 1e9 + 7;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // 你的代码
    int n;
    cin >> n;

    return 0;
}

9. 常见错误速查

错误原因解决方法
加速后 cin/printf 混用输出乱序关闭同步后两套缓冲区独立统一用 cin/cout 或 scanf/printf
交互题 WA/TLE输出未及时刷新用 endl 或 cout << flush
用了 endl 导致超时endl 每次 flush 很慢改为 '\n'
文件模式忘记关闭 freopen本地测试正常,提交时 RE提交前检查是否需要去掉 freopen
bits/stdc++.h 在 MSVC 报错MSVC 不支持此头文件本地用具体头文件,或安装 MinGW/GCC

适用范围:NOI / NOIP / CSP / 蓝桥杯 / Codeforces 等竞赛,编译器 GCC 11+。

推荐阅读

3月15日·4 分钟

信息学竞赛时间线与升学规划

NOI时间线
5月20日·3 分钟

算法复杂度速查手册

算法基础知识算法复杂度
3月27日·2 分钟

排序算法详解:从冒泡到快速排序

算法排序

目录

  • 1. 头文件策略
  • 1.1 万能头文件
  • 1.2 常用头文件速查
  • 2. 命名空间
  • 3. 输入输出加速
  • 3.1 为什么 `cin` 默认很慢?
  • 3.2 两行加速代码
  • 3.3 逐行解析
  • 3.4 加速效果对比
  • 3.5 标准模板
  • 4. `'\n'` vs `endl`
  • 5. 手写快读(极限优化)
  • 6. 文件输入输出
  • 7. 交互题特殊处理
  • 8. 完整竞赛模板
  • 9. 常见错误速查