当你在信息学竞赛((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 >> n
或scanf("%d", &n)
改成n = read()
即可!
原理分析
为什么(cin)慢?因为它需要和(stdio)保持同步,也就是sync_with_stdio
。
为什么(scanf)慢?原因有点复杂。
- 它可以接受多种形式的输入(数字、字符串等等),因此需要判断。
- 它因为某些安全原因——输入太快可能会有些玄学的(bug),具体的我也不太清楚。
其实在(C++)中,依次读入单个字符是比一次读入一个数要快的,因此我们可以用(getchar())来负责读入。
在实际的文件中,会有许多不必要的隐藏字符,比如换行符
等。
因此,我们需要先排除掉这些字符,也就是第一个(while)循环。但是有一个特例:(-21904)中的(-)号。这个负号不是数字啊!于是我们用(w)当数的符号。有负号时,(w)从原来的(1)转化成了(-1)。
于是,我们要特判!if(ch == ‘-’) w = -1;
这就是判负号的语句。
下一个循环中,就是位值原理。数(overline{abcd} = 10 imes (10 imes (10 imes a + b) + c) + d),读者自证不难。
最后返回(n = sgn(n) imes |n|),其中(sgn(x))为(x)的符号。