奇技淫巧:NOIP的读入优化

最近看到洛谷上面有一个读入优化的代码:

inline char get_char(){//劲者快读
    static char buf[1000001],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline short read(){
    short num=0;
    char c;
    while(isspace(c=get_char()));
    while(num=num*10+c-48,isdigit(c=get_char()));
    return num;
}

说实话第一个函数get_char的第二行,这么长一六三目运算符真心看不懂

(下面的read函数里面那个isspace()和isdigit()就是判断这个字符是不是空格,是不是数字,是的就返回true,不是返回false。你看多没用的函数= =)

然后我就把代码百度了一下,发现还真有类似的东西:

inline char NC(void)
{
  static char buf[100000], *p1 = buf, *p2 = buf;
  if (p1 == p2) {
    p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);
    if (p1 == p2) return EOF;
  }
  return *p1++;
}

于是研究了一会,发现这是一个极其神奇的读入优化

一般来说我们读入都用的scanf和cin,实在必要的时候可以用getchar读入优化。

然后众所周知,cin比scanf慢,getchar最快。

但是到底差距有多大很多人都不知道。

于是上个星期我做了一个贼有意思的测试,把scanf、cin、getchar(分为宏定义函数和内联函数两个)分别读入1000000个数,然后输出运行时间。

getchar的两个函数贴在这里:

#define gi(a) do { \
  register char ch;   while((ch = getchar()) > ‘9‘ || ch < ‘0‘);   for(a = ch-‘0‘; (ch = getchar()) >= ‘0‘ && ch <= ‘9‘; a = a*10+ch-‘0‘);   }while(0)
inline void gi2(int &a) {
    register char ch;
    while((ch = getchar()) > ‘9‘ ||ch < ‘0‘);
    for(a = ch-‘0‘; (ch = getchar()) >= ‘0‘ && ch <= ‘9‘; a = a*10+ch-‘0‘;
}
//(仅限正整数)

发现scanf大概比cin快2倍,getchar比cin快5倍。

其中宏定义的getchar稍稍比内联的getchar快那么一点点点点。

然后就是今天我看到的玄学优化了。

https://www.byvoid.com/zhs/blog/fast-readfile

这里有所有读入的速度评估(看来我还不是第一个干这种贼有意思的事情的wwww)

经过实测,这种优化比scanf快了10倍!

这个读入用的是fread,我百度了一下,这是一种直接把文件所有字符全部读入的一个函数。

函数原型是这样的:

size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;

可以看到有四个参数,分别是读入的数组,读入每个数据项的字节数,读入的个数,以及读入的文件stream。

返回的是读到的数据项的个数。

此外还有个static关键字,就把它看成是函数里面的全局变量就行了,也就是说再用一次这个函数,里面的值不会变的。

此外static只有在第一次定义的时候才能赋值,之后调用的时候赋值是无效的,也就是说之后的调用函数这个赋值那一行是没用的。

这里还有个点,看这一行:

p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);

这里的=号的返回值就是赋值号右边的那个值,也就是buf的值。

那么就等于写成这样:

p1 = buf;
p2 = buf+ fread(buf, 1, 100000, stdin);

在我们一开始调用函数的时候,p1 p2都被赋值为buf的数组开始的位置,之后进入if语句,p2变成数据最后的位置(开始的位置+数据的长度 = 最后的位置)。

然后随着每次返回,p1都会往前面移动一个,直到p1也遍历到了最后的位置,p1 == p2

这时候再次进入if语句,然后同样p2变成数据最后的位置,因为p1这时也是数据最后的位置了,所以p1照样==p2,于是数据遍历结束了,返回文件结束符EOF.

就这样,完美模拟一次文件读写~

然后把if语句简化就变成了那个很长一六的三目运算符:

inline char get_char(){//劲者快读
    static char buf[1000001],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}

可以把这个模板背一下,然后就直接套自己的getchar读入优化模板了。

当然也可以把这里面的static索性全部拿到外面去,变成全局变量,然后做一个宏定义:

char buf[1000001],*p1=buf,*p2=buf;
#define get_char() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)

虽说这样肯定比内联函数快,但是因为宏定义毕竟是机械式替换的……所以不保证不出玄学bug,慎用。(不过一般来说用我自己写的模板不会有问题)

(其实我不会把只有一行语句的宏用do while(0)封装起来,所以只能打个括号完事)

这个优化虽然快是快,但是因为奇技淫巧……不保证不出bug,所以还是谨慎使用。

就当做普及一个玄学优化吧。

最后贴上我把这个玄学优化写进我的玄学getchar里面弄出的超级巨型玄学贼有意思奇技淫巧读入优化

char buf[1000001],*p1=buf,*p2=buf;
#define get_char() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define gi(a) do { \
  register char ch;   while((ch = get_char()) > ‘9‘ || ch < ‘0‘);   for(a = ch-‘0‘; (ch = get_char()) >= ‘0‘ && ch <= ‘9‘; a = a*10+ch-‘0‘);   }while(0)
时间: 2024-08-29 09:35:00

奇技淫巧:NOIP的读入优化的相关文章

关于读入优化的最终分析

关于读入优化的最终分析 摘要 身为一只以卡常为生的蒟蒻,总想着通过一些奇技淫巧来掩饰优化常数. 于是本文章就非正式地从最初的开始到最终的终止来谈谈在OI种各种主流.非主流读入的速度以及利弊. 序言 随着算法的发展各种数据结构等劲题出现,这些题除了思维难度的提高还带来者输入数据的增多(特别的有:uoj.ac上的一道题需要选手自己生成数据,而数论题往往输入较少),对于有追求有理想的选手快速读入是必不可少的技能. 尽管市面上有不同的主流读入优化,但是大多都是基于fread的,其余的只是一些小变动. 而

【墙裂推荐】读入优化和输出优化

读入优化: 1 inline int read() 2 { 3 int X=0,w=1; char ch=0; 4 while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();} 5 while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar(); 6 return X*w; 7 } 输出优化: 1 inline void write

bzoj3685: 普通van Emde Boas树 set+读入优化

显然这题的所有操作都可以用set,但是直接用set肯定要T,考虑到读入量较大,使用fread读入优化,就可以卡过去了. #include<bits/stdc++.h> using namespace std; void read(int& x){ const int k=1600000; static char v, u[k],*s=u,*t=u; x=0; while(isspace(v=s==t &&u==(t=u+fread(s=u, 1,k,stdin))?-1

OI中整数的读入优化

将整数一个字符一个字符地读入,再转成整数,比直接作为整数读入快. 在读入大规模的整数数据时比较有效. 代码如下: inline void read_int(int &num) { char c; while (c = getchar(), c < '0' || c > '9'); num = c - '0'; while (c = getchar(), c >= '0' && c <= '9') num = num * 10 + c - '0'; } OI中

一些常见的优化:读入优化,滚动数组

1.读入优化 我们平时所使用的scanf,cin速度都较慢,当读入的数据达到10^5规模以上时,就会开始显现劣势 而c中自带的getchar函数读入速度较快,可以用来优化数字的读入速度. 1 inline int get_num() 2 { 3 int num = 0; 4 char c; 5 bool flag = false; 6 while ((c = getchar()) == ' ' || c == '\n' || c == '\r'); 7 if (c == '-') flag =

读入优化模板

读入优化: int get_val() { int ret=0; char c; while((c=getchar())!=' '&&c!='\n') ret=ret*10+c-'0'; return ret; }

【日常学习】【读入优化】codevs2555 a+b=?题解

题目很简单 题目描述 Description 做了,简单的a,b和的问题.但是,如果要求输入的情况不是a和b,而是整个加法表达式呢? 请想办法,计算加法表达式的结果. 输入描述 Input Description 输入一个加法表达式,如1+2=. 输出描述 Output Description 计算出输入表达式的正确结果 样例输入 Sample Input 1+2= 样例输出 Sample Output 3 数据范围及提示 Data Size & Hint 完整的输入表达式.加号两边的数值属于-

读入优化 &amp;&amp; 输出优化

qwq算是一个板子随笔吧 快读我在某大佬的博客中找到了更短的代码 但是这个写习惯了就改不了了qwq 其实是我不想改 废话好多 直接贴代码 1 //读入优化 2 inline int read(){ 3 char ch, c; 4 int res; 5 while (ch = getchar(), ch < '0' || ch > '9') c = ch; 6 res = ch - 48; 7 while (ch = getchar(), ch >= '0' && ch &

读入优化&amp;输出优化

读入优化:读入优化只是针对整数,由于getchar()读字符非常的快,所以采用getchar()来进行读入,下设输入的数为x 负数处理:用一个标志变量f,开始时为1,当读入了'-'时,f变为-1,最后x*=f即可 绝对值部分处理:getchar()每次只能读一位,所以每当读了一位s时,x*=10,为s留位置,由于s为字符,需要减去'0'才能转为整数即:x=x*10+s-'0' 关于细节: 很多时候有多余的空格或者其它的一些无关字符输入,处理时需要注意排除 代码: 1 void read(int