快速 I/O 与竞赛模板
这部分作为提交时的查阅清单。初学者可先运行两整数求和的输入输出例子,再顺序学习正文;学过函数、类型和头文件后,回来理解通用模板中的每一行,不需要先掌握整份模板才能开始语言基础。
标准流加速
大多数入门题使用下面两行设置已经足够。把它们放在 main 开头、任何输入输出之前。
快在哪里? C 与 C++ 标准流保持同步、读入前自动刷新关联输出,都可能产生额外工作。普通批量题只需把输入一次次读完、最后按规则输出,所以可以关闭这两项配合;它们不改变题目的计算逻辑。
模板在 main 开头先设置标准流,再用 cin、cout 完成输入输出。关闭同步后,C 与 C++ 的标准流各自使用缓冲;例如 scanf 已把一段输入读进自己的缓冲,cin 再读取时就可能接不到这段数据。因此,下面的标准流模板从读入到输出都使用 cin、cout,后面的 fread 模板则使用 C 输入输出。
'\n' 只写换行字符,endl 还会强制刷新。大量输出时,逐行刷新会增加开销;交互题中,程序输出询问后刷新,另一端收到询问才能继续回答,因此询问后可以使用 endl 或 cout.flush()。
#include <iostream>
using namespace std;
ios::sync_with_stdio(false); // 关闭 C 与 C++ 标准流同步。
cin.tie(nullptr); // 读入前不再自动刷新 cout。sync_with_stdio(false)关闭 C++ 标准流与 C 标准流的同步。cin.tie(nullptr)取消cin默认关联的输出刷新。cout默认没有绑定输入流,通常不需要额外写cout.tie(nullptr)。endl会换行并刷新,普通批量输出使用'\n'即可。
注意: 交互题需要在输出询问后主动刷新,例如
cout << query << '\n' << flush;。取消自动刷新以后,忘记刷新可能让双方一直等待。
基础竞赛模板:使用 ll 类型别名
下面适合 GNU C++17 等支持 bits/stdc++.h 的评测环境。每题先确认是否有多组输入,再决定是否读取 T。
#include <bits/stdc++.h> // GNU 扩展,非标准头文件
using namespace std;
using ll = long long;
void solve() {
// 每组数据的变量尽量放在这里,自动重新初始化
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
// cin >> T; // 题目明确给出测试组数时开启
while (T--) {
solve();
}
return 0;
}如果评测要求可移植的标准 C++,把第一行换为当前程序实际需要的标准头文件;只做整数输入输出时使用 <iostream> 即可。
竞赛宏模板:统一使用 long long
下面是一份常用的竞赛宏模板。可以与显式 ll 模板择一使用:
#include <bits/stdc++.h> // 需要支持这个扩展头文件的 GNU 环境。
#define int long long // 将后续 int 统一替换成 long long。
#define endl '\n' // 仅换行,不刷新输出。
using namespace std;
void solve() {
// 在这里实现一组数据的解法。
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
solve();
}说明:
#define int long long是预处理阶段的文本替换,不是类型别名。后续声明中的 int 会统一使用较宽整数,估算数组内存时按实际元素大小计算;学习 STL 后也按容器实际元素类型估算。signed main()中的signed表示signed int,没有显式的int记号,因此不会被宏替换;main仍返回标准要求的int。若写int main(),返回类型也会被替换,因此模板使用signed main()。- 宏不会把字面量
1自动变成1LL。例如1 << 40的左操作数仍是普通int,应根据需要写为1LL << 40或1ULL << 40。 #define endl '\n'取消了刷新作用;后续写std::endl还会被替换成非法代码。需要刷新时使用flush。- 这个类型宏还会改变重载、接口匹配和类型组合。例如
scanf("%d", &x)不再匹配替换后的long long x。通用讲解示例使用ll或显式long long,更容易看清类型。 cin.tie(0), cout.tie(0);使用逗号表达式执行两次调用,0在这里表示空指针;现代写法可使用nullptr。
这份模板适用于常见 GNU C++ 竞赛环境。统一整数类型可以减少累计和与乘法的类型遗漏;调试接口、移位和内存问题时,仍要按宏替换后的实际类型检查。
多组输入、EOF 与输出精度
有明确测试组数:
#include <iostream>
using namespace std;
void solve() {
// 示例每组读入两个整数,真正做题时替换为当前题目的解法。
long long a, b;
cin >> a >> b;
cout << a + b << '\n'; // 输出这一组两数之和。
}
int main() {
int T;
cin >> T;
while (T--) {
solve(); // 每次调用处理恰好一组数据。
}
}没有组数,读到文件结束:
下面每组读入两个整数,用 long long 保存并输出它们的和。
#include <iostream>
using namespace std;
int main() {
long long a, b;
while (cin >> a >> b) {
cout << a + b << '\n'; // 每次成功读到一对数,处理恰好一组。
}
}while(cin>>a>>b) 把“本次完整读入成功”作为继续条件。EOF 表示输入结束,格式错误也会令读取失败。不要先判断 !cin.eof() 再读取;末尾标志通常在一次读取尝试后才设置,可能多处理一组旧数据。读到一组数据的中途就结束时,循环条件为假,这一组不会进入计算。
输出固定小数位:
#include <iostream>
#include <iomanip>
using namespace std;
double answer = 1.0 / 3.0;
// fixed 下的精度表示小数点后 6 位,输出 0.333333。
cout << fixed << setprecision(6) << answer << '\n';注意: 每组数据开始时重新初始化它需要的数组、计数器和答案,避免上一组结果影响下一组。后面学习容器后,也要按每组数据的实际长度重新准备存储。