快速读入详解

当你在信息学竞赛\((OI)\)中进入了提高组时,你可能会被卡常!

卡常!

程序被卡常数,一般指程序虽然渐进复杂度可以接受,但是由于实现/算法本身的时间常数因子较大,使得无法在OI/ICPC等算法竞赛规定的时限内运行结束。

常数被称为计算机算法竞赛之中最神奇的一类数字,主要特点集中于令人捉摸不透,有时候会让水平很高的选手迷之超时或者超空间。

​ ——来自某度百科……

快速读入

简称快读,是信息学竞赛中卡常数最为常见的方法。

一般来讲,大多数题目的出题人都不会到这种丧心病狂的地步。

不过,以防万一肯定没坏处啊~ 反正代码很简单啦

代码

先上代码!讲解在后面。

inline int read(){
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
    return s * w;
} // 这是能判负数的C++快读模板

在代码中,只需将cin >> nscanf("%d", &n)改成n = read()即可!

原理分析

为什么\(cin\)慢?因为它需要和\(stdio\)保持同步,也就是sync_with_stdio

为什么\(scanf\)慢?原因有点复杂。

  1. 它可以接受多种形式的输入(数字、字符串等等),因此需要判断。
  2. 它因为某些安全原因——输入太快可能会有些玄学的\(bug\),具体的我也不太清楚。

其实在\(C++\)中,依次读入单个字符是比一次读入一个数要快的,因此我们可以用\(getchar()\)来负责读入。

在实际的文件中,会有许多不必要的隐藏字符,比如换行符\n等。

因此,我们需要先排除掉这些字符,也就是第一个\(while\)循环。但是有一个特例:\(-21904\)中的\(-\)号。这个负号不是数字啊!于是我们用\(w\)当数的符号。有负号时,\(w\)从原来的\(1\)转化成了\(-1\)

于是,我们要特判!if(ch == ‘-’) w = -1;这就是判负号的语句。

下一个循环中,就是位值原理。数\(\overline{abcd} = 10 \times (10 \times (10 \times a + b) + c) + d\),读者自证不难。

最后返回\(n = sgn(n) \times |n|\),其中\(sgn(x)\)\(x\)的符号。

posted @ 2018-12-28 20:30  P_Wang  阅读(2627)  评论(4编辑  收藏  举报