在 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;
}
这些输入输出方法可以根据题目的数据规模灵活选择,在保证正确性的前提下最大化程序运行效率。
妈妈再也不用担心我暴力拿不了高分啦ヾ (▽*)
