必要性
总所周知 , 在毒瘤大数据面前 , scanf/printf
很慢 , cin/cout
更慢 . 所以目前有两种主流的快读快写 , getchar/putchar
( putchar
有时甚至不如 printf
) 和 解绑 ios
.
至于 cin/cout
( 不解绑的情况下 ) 为什么慢 , 这里不多阐述 ( 也相信你点进来不是为了这个 ) .
顺便一提 , 在某些评测姬上 , 解绑 cin/cout
特别能吃 $buff$ , 在处理字符上比 fread/fwrite
快了不知道多少 . $→$ 刷题时 $2e7$ 范围的字符 , $T$ 了三个点 , 后来才发现是 fread/fwrite
太酷慢啦 !
$\text{速度比较}$
$\text{输入}$
$n = 1e9$ , 采用 $mt19937$ 生成随机数 , 保证所有数据在 int
范围内 , 三次取最快 , 保留 $3$ 位小数 .
冷笑话 : $10.3G$ ( $1e9$ ) 的数据把我可怜的 $16G$ 内存条干爆了 ( 后来用浏览器打开的 ) .
cin : 876.288s
scanf : 335.884s
getchar : 159.953s
解绑cin : 87.893s
fread : 38.521s
显而易见的 , fread
占据了上风 . 另外 , 值得注意的是 : getchar
与 解绑cin
( 本文后面将不再讨论 cin/cout
与 scanf
的速度差异 , 并且后文将简称 cin/cout
为 解绑cin/cout
) 差了 $2$ 倍左右 . 而将 cin
解绑仅需要一行 :
ios::sync_with_stdio(NULL),cin.tie(NULL),cout.tie(NULL);
// NULL 可以替换为 0 , 这里用 NULL 只是习惯的问题 .
但 getchar
在不压行的情况下比 cin
多得多 :
template <typename T>
inline auto Read(T &variable) -> void {
variable = 0;
bool negative = false;
char charact;
do {
charact = getchar();
negative ^= charact == '-';
}while(!isdigit(charact));
while(isdigit(charact)) {
variable = (variable << 1) + (variable << 3) + (charact ^ 0x30);
charact = getchar();
}
if(negative) variable = ~variable + 1;
}
// 其实可以更短 , 但是个人感觉这样写更好看些 ( 雾
所以 , 在背不到 fread/fwrite
的模板时 , cin/cout
才是永远的神 .
再来看一组较小的数据 ( 毕竟没有哪道题会出这么毒瘤良心的数据来恶心人 , 所以还是把数据放正常点 ) .
$n = 1e7$ , 其余条件与 $n = 1e9$ 时一样 .
getchar : 1.610s
cin : 0.880s
fread : 0.392s
可以看到 , 这次 getchar
比 cin
慢了 $2$ 倍不止 .
那么 , 再见 , getchar
.
$\text{输出}$
printf :
putchar (递归) :
putchar (栈) :
cout :
fwrite :
$\text{附录}$
$\text{测试环境}$
处理器 12th Gen Intel(R) Core(TM) i9-12900H 2.50 GHz
机带 RAM 16.0 GB (15.7 GB 可用)
系统类型 64 位操作系统, 基于 x64 的处理器
版本 Windows 11 家庭中文版
版本 22H2
操作系统版本 22621.1702
体验 Windows Feature Experience Pack 1000.22641.1000.0