c++算法竞赛输入输出优化
在 C++ 算法竞赛中,输入输出的速度往往是影响程序性能的关键因素
其实主要是用来优化暴力代码的啦o(///▽///)q
下面我将给出几组常用输入输出板子
Part-1. 标准输入输出
大家对这个应该很熟悉了吧?想必最开始接触 OI的时候大家写的输入输出就是用的这个吧。
#include <iostream>
using namespace std;
int main() {
int a;
cin >> a; // 输入
cout << a << endl; // 输出
return 0;
}
其实你做多了题目就会发现这个cin和cout是非常慢的,因为它从缓冲区中读入数据,而这个缓冲常常是同步的,因为它还需要辨别输入类型。
为了加速这东西,所以我们可以在代码中加入这样几句话,意为关闭同步流:
ios::sync_with_stdio(false); // 解除cin与stdin的绑定
cin.tie(0); // 解除cin与cout的绑定
cout.tie(0); // 解除cout与cin的绑定
但是在大量的数据面前,它的表现仍然不够出色,常常有TLE的存在。
所以就有了下面这个东西
Part-2.\(scanf\) and \(printf\)
scanf/printf 是大多数有经验的 OIer 常用的输入输出方式。
由于需要加上格式符,它不太受广大初学者喜欢。
但请注意:它很快!
不过它也有一个缺点,相信很多做过字符串题目的 OIer 都清楚 ——scanf 可能会读入换行符!
这里解释下原因:
Linux 和 Windows 下的换行符是不一样的!
至于具体哪里不一样,读者可以查阅网上资料,这里只做原因解释。因此,如果要读入字符且涉及换行等情况,建议先读一句:
scanf ("\n");
这样基本就没什么问题了 QAQ。
等等,你不是说它很快吗?为什么我在处理超过 100w 数据时,会因为它而 TLE 呢?
因为它还不够快!
Part-3. 手写快读快写
利用getchar()和putchar()函数实现,速度比标准 IO 快很多:
不过相对于上面两种来说会难写的多,不过提升也是相对而言比较可观的
#include <cstdio>
#include <cstring>
// 快读
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * f;
}
// 快写
inline void write(int x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
// 快写带换行
inline void writeln(int x) {
write(x);
putchar('\n');
}
Part-4. 手写\(Super快读\) and \(Super快写\)
进一步优化,利用缓冲区批量读取和写入,速度超级快,适合处理超大量数据
不过这个难写程度嘛。。。。。。
还是自己体会一下吧。
#include <cstdio>
#include <cstring>
// 超级快读
namespace fastIO {
const int BUF_SIZE = 1 << 20;
char buf[BUF_SIZE], *p1, *p2;
// 获取一个字符
inline char gc() {
if (p1 == p2) {
p1 = buf;
p2 = buf + fread(buf, 1, BUF_SIZE, stdin);
}
return p1 == p2 ? EOF : *p1++;
}
// 读取整数
inline int read() {
int x = 0, f = 1;
char ch = gc();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = gc();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = gc();
}
return x * f;
}
// 读取长整数
inline long long readll() {
long long x = 0, f = 1;
char ch = gc();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = gc();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = gc();
}
return x * f;
}
}
// 超级快写
namespace fastIO {
char obuf[BUF_SIZE], *pO = obuf;
// 刷新缓冲区
inline void flush() {
fwrite(obuf, 1, pO - obuf, stdout);
pO = obuf;
}
// 写入一个字符
inline void pc(char c) {
if (pO - obuf == BUF_SIZE) flush();
*pO++ = c;
}
// 写入整数
inline void write(int x) {
if (x < 0) {
pc('-');
x = -x;
}
if (x > 9) write(x / 10);
pc(x % 10 + '0');
}
// 写入长整数
inline void writell(long long x) {
if (x < 0) {
pc('-');
x = -x;
}
if (x > 9) writell(x / 10);
pc(x % 10 + '0');
}
// 写入字符串
inline void write(const char *s) {
while (*s) pc(*s++);
}
// 写入换行
inline void writeln() {
pc('\n');
}
}
// 程序结束时自动刷新缓冲区
struct FastIOInitializer {
~FastIOInitializer() {
fastIO::flush();
}
} fastIOInitializer;
使用说明
标准 IO 适合简单题目,但数据量大时会超时
快读快写适用于大多数算法竞赛题目,速度足够快
超级快读超级快写适用于数据量极大的场景(如 1e6 级别以上数据)
使用时只需将对应的函数包含在代码中,然后直接调用即可啦:
int main() {
int a = fastIO::read(); // 超级快读
long long b = fastIO::readll(); // 读取长整数
fastIO::write(a); // 超级快写
fastIO::writeln(); // 换行
return 0;
}
这些输入输出方法可以根据题目的数据规模灵活选择,在保证正确性的前提下最大化程序运行效率。
妈妈再也不用担心我暴力拿不了高分啦ヾ (▽*)

浙公网安备 33010602011771号