头文件与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 默认做了两件事:
- 与 C 的 stdio 同步:保证
cin和scanf混用时输出顺序正确。这会导致cin每次操作都要刷新 C 缓冲区,大幅降速。 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 加速效果对比
在读取 个整数的场景下(参考值,实际因机器和数据而异):
| 写法 | 相对速度 |
|---|---|
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. 手写快读(极限优化)
当数据规模达到 级别,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+。