快读

某些题中,读入数据往往比较繁多,故输入是一大难题,有时会遇到一些读入困难,cin与scanf也许都解决不了,这时掌握快读是必要的。

基本快读思想如下(分析整数):

一位一位读入,对当前读入字符进行分析,

先判断首位是否为负号,并进行相应处理,

如果读入的为数字,将其做处理后存入,

遇到空格视为停止,返回所存值(return)。

一般快读代码如下:

#include<bits/stdc++.h>
using namespace std;
#define mod 10000007 //取模数据,一般大数据题目会做要求
int read(){    //快读多被定义为long long
    int f=1;   //存负
    int x=0;
    char c=getchar();
    while(c<'0'||c>='9'){
        if(c=='-') f=-1;
        c=getchar();     //不断读入,直到读入字符在0-9范围内
    }
    while('0'<=c&&c<='9'){
        x=x*10+c-'0';    //将原来的数据*=10,借此把新数字当做个位存放
        x%=mod;          //取模
        c=getchar();     //读入下个字符,如果下个字符非数字,则跳出,快读结束
    }                    //只要输入合法,快读处理数据就一定正确,毕竟合法输入的同一整数之中不存在除数字外的其他符号
    return x*f;
}
int main(){
    int a=read();
    cout<<a;
    return 0;
}

然而这在一般快读中并不是最快的,主要优化有以下几点:

1. 对于它

int read()

可以在int前加上inline,inline对于多次调用的函数有着非常明显的加速作用,而明显快读非常常用,inline具体原理大概是将该函数在任意调用处展开,详细原理还是的上网查吧

2.对于

 x=x*10+c-'0';

数据的四则运算固然简单,然而比起位运算要慢

(位运算就是将数据以二进制(毕竟计算机认得二进制)进行运算)

二进制比十进制计算是要快一点的,

所以可以改成下面这样:

 x=(x<<3)+(x<<1)+(c^48);

其中,x<<n表示x的二进制向左移动n位,空位补0,相当于x*=2n

这里的(x<<3)+(x<<1)相当于

  x*23+x*21,

=x*(8+2)

=x*10

而c^48则是“异或运算”

即二进制对应位置不同时该位为1,否则为0

即判断对应数位是否不同

1 0 0 1 0 1 1 0与

1 1 0 0 1 1 0 1两数运算结果为

0 1 0 1 1 0 1 1,

因其算法具体为0^0=0,0^1=1,1^0=1,1^1=0

像是二进制的加法,但没有进位,所以被称作(二进制)不进位加法

这里的c^48则是特殊情况,因为‘0’=48,而48=(110000)2

众所周知,后面四位能表示的最大十进制整数为15,故表示ACSII码中的10个数字绰绰有余

并且因为48-57中,二进制形式其第五第六位皆为1,所以进行异或运算时会被算为0,即48-57中每个数由于都含有这两位数,都减去了48,而48的后面4位全是0,故49-57的数与48的差异能且仅能在后四位体现,从48-57,后四位恰好组成0-9,且一一对应,故可用^运算来进行数字的ASCII码转换。

这里加上c^48等同于将此字符所代表数字做个位加进去,而位运算相当快,所以。。。

这算是“快读”

posted @ 2019-04-09 11:43  _Alex_Mercer  阅读(901)  评论(0编辑  收藏  举报