源码
此处展示的是 2.0 版本源码:
template<typename Tp> inline void read(Tp &x) {x=0; register bool z=true; register char a=getchar_unlocked(); for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=false; for(;isdigit(a);a=getchar_unlocked()) x=(x<<1)+(x<<3)+(a^48); x=(z?x:~x+1);}
inline void read(double &x) {x=0.0; register bool z=true; register double y=0.1; register char a=getchar_unlocked(); for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=false; for(;isdigit(a);a=getchar_unlocked()) x=x*10+(a^48); if(a!='.') return x=z?x:-x,void(); for(a=getchar_unlocked();isdigit(a);a=getchar_unlocked(),y/=10) x+=y*(a^48); x=(z?x:-x);}
inline void read(char &x) {for(x=getchar_unlocked();(!(x^32)||!(x^10)||!(x^13))&&(x^-1);x=getchar_unlocked());}
inline void read(bool &x) {register char a=getchar_unlocked(); for(;!isdigit(a);a=getchar_unlocked()); x=a^48; for(;isdigit(a);a=getchar_unlocked());}
inline void read(char *x) {register int len=0; register char a=getchar_unlocked(); for(;(!(a^32)||!(a^10)||!(a^13))&&(a^-1);a=getchar_unlocked()); for(;(a^32)&&(a^10)&&(a^13)&&(a^-1);a=getchar_unlocked()) x[len++]=a; x[len]='\0';}
inline void read(string &x) {x=""; register char a=getchar_unlocked(); for(;(!(a^32)||!(a^10)||!(a^13))&&(a^-1);a=getchar_unlocked()); for(;(a^32)&&(a^10)&&(a^13)&&(a^-1);a=getchar_unlocked()) x+=a;}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y) {read(x),read(y...);}
template<typename Tp> inline void write(Tp x) {if(x<0) putchar_unlocked('-'),x=~x+1; register int len=0; register char tmp[64]; for(;x;x/=10) tmp[++len]=x%10+48; while(len) putchar_unlocked(tmp[len--]);}
inline void write(double x) {register int a=6; register double b=x,c=b; if(b<0) putchar_unlocked('-'),b=-b,c=-c; register double y=5*powl(10,-a-1); b+=y,c+=y; register int len=0; register char tmp[64]; if(b<1) putchar_unlocked(48); else for(;b>=1;b/=10) tmp[++len]=floor(b)-floor(b/10)*10+48; while(len) putchar_unlocked(tmp[len--]); putchar_unlocked('.'); for(c*=10;a;a--,c*=10) tmp[++len]=floor(c)-floor(c/10)*10+48; for(int i=1;i<=len;i++) putchar_unlocked(tmp[i]);}
inline void write(pair<int,double>x) {register int a=x.first; if(a<7) {register double b=x.second,c=b; if(b<0) putchar_unlocked('-'),b=-b,c=-c; register double y=5*powl(10,-a-1); b+=y,c+=y; register int len=0; register char tmp[64]; if(b<1) putchar_unlocked(48); else for(;b>=1;b/=10) tmp[++len]=floor(b)-floor(b/10)*10+48; while(len) putchar_unlocked(tmp[len--]); a&&(putchar_unlocked('.')); for(c*=10;a;a--,c*=10) tmp[++len]=floor(c)-floor(c/10)*10+48; for(int i=1;i<=len;i++) putchar_unlocked(tmp[i]);} else cout<<fixed<<setprecision(a)<<x.second;}
inline void write(char x) {putchar_unlocked(x);}
inline void write(bool x) {putchar_unlocked(x?49:48);}
inline void write(string &x) {fputs(x.c_str(),stdout);}
inline void write(char *x) {fputs(x,stdout);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y) {write(x),write(y...);}
代码长度 \(2.9k\),如果您不想让自己的代码开局上百行的话建议保持这种每个函数压成一行的形式。
写在前面
-
有更加简洁的 1.0 版本,但是只支持对于整形的输入输出,读入效率与 2.0 版本完全相同,输出效率略低于 2.0 版本,详见 一些工具。
-
2.0 版本的存在意义在于在保证了相对较高的效率同时更加方便使用,以避免了需要输出非整形时还需要使用其他读写方式从而降低了效率且不方便使用的问题,而非最求最快,所以在极端卡常环境下作用可能没有一些“超级快读”显著。
-
绝大多数函数基于
getchar_unlocked
和putchar_unlocked
实现,没有采用fread
和fwrite
的原因是不想让输入输出占用格外的空间,所以效率方面有一定的保证但难以达到最快。同时
getchar_unlocked
和putchar_unlocked
只能在 linux 环境下使用,若评测环境为 windows 请将其更换为getchar
和putchar
,但这样的话效率大大下降,不如直接用解绑cin
、cout
。不管什么评测环境,请勿将其和解绑
cin
、cout
同时使用,原因可自行上网查询。同时,对于每一个函数,请保证您的传参是合法的,否则出现死循环等问题一概不负责。
-
对于
double
的输出是存在精度误差的,但是在保留小数点后 \(6\) 位及以内的数据正确率约为 \(100\%\),但是在 \(7\) 位及以上时,即使使用printf
也会存在精度问题,单位了避免不必要的麻烦,对于 \(7\) 位及以上的,我使用了cout<<fixed<<setprecision(a)<<b
,\(a\) 为保留位数,\(b\) 为输出的数,这个cout
是没法解绑的,但是效率没有比解绑的低太多,所以当其出现精度问题时并不是快写的问题。 -
经过调试,目前应该没有大的问题,若存在问题请及时指出,我会尽快改正,后续可能要优化代码所以可能会更新版本。
功能介绍
-
支持对于整形的输入,您可以使用
read(x)
读入一个整形 \(x\),效率保证通过 P10815【模板】快速读入。 -
支持对于
double
的输入,不支持对于float
的输入,您可以使用read(x)
输入一个double
类型的 \(x\),效率与对整形输入类似。 -
支持对于
bool
的输入,您可以使用read(x)
输入一个整形 \(x\),若您输入的 \(x\) 为合法的整形,其将自动识别为bool
类型,若为 \(0\) 或 \(-0\) 则识别为false
,否则为true
,效率与对整形输入效率类似。 -
支持对于字符的输入,自动过滤空格与换行,您可以使用
read(x)
读入一个字符 \(x\),如果您想读入一个空格或换行请使用gatchar
等自带函数。 -
支持对于字符串的输入,包括一维
char
数组(char*
)和string
,您可以使用read(x)
输入一个字符串 \(x\)。效率方面,基于 \(O(len)\) 次的
getchar_unlocked
,约为scanf
的 \(2\) 倍,约为不解绑cin
的 \(10\) 倍,但只有不解绑cin
的 \(\dfrac{1}{2}\),目前没有想到更好的解决方案,欢迎大家指出。同时不管什么读入方式对于字符串的输入效率都是极高的,不必担心输入字符串被卡常,实测 \(10^9\) 个字符的量只需要 \(0.5s\) 左右。 -
支持多个类型同时输入,具体的,您可以使用
read(a,b,c,...)
依次进行 \(a,b,c\) 等若干个任意类型的输入。特殊的,对于一个
char*
类型的 \(s\),您可以正常的将 \(s\) 传入该函数,但不支持将其类似与 \(s+1\) 的类型传入上述函数,因为我对于输入类型均进行了取地址,而 \(s+1\) 本身就是一个地址,不能够重复两次取地址,存在解决方案但是并不优美,因为我并不想在每个变量前都手动加一个取地址,所以在不影响其他类型输入的手感的前提下,请单独使用read(s+1)
。 -
支持对于整形的输出,您可以使用
write(x)
输出一个整形 \(x\),相对于 1.0 版本的提升在于将其从递归改为递推,从而提高了效率,效率高于解绑的cout
。 -
支持对于
double
的输出,不支持对于float
的输出,您可以使用write(x)
输出一个double
类型的 \(x\),效率高于printf
和解绑的cout
,精度问题已在前面阐述。 -
支持对于
bool
的输出,您可以使用write(x)
输出一个bool
类型的 \(x\),若 \(x=true\) 输出1
,若 \(x=false\) 输出0
。 -
支持对于字符的输出,您可以使用
write(x)
输出一个字符 \(x\),本质就是把 \(x\) 直接putchar_unlocked
出去。 -
支持对于字符串的输出,包括一维
char
数组(char*
)和string
,您可以使用write(x)
输出一个字符串 \(x\)。此函数不基于
getchar_unlocked
而是基于fputs
,因为对于一个一个字符的输出效率是严格低于整个输出的,使用fputs
的效率极高,和解绑的cout
几乎相同。也正因为使用了
fputs
,若您想要输出的是一个char*
,请保证其末尾字符为\0
。另外,我对字符串的输出进行了取地址操作,不会占用格外的空间。
-
支持多个类型同时输出,具体的,您可以使用
write(a,b,c,...)
依次进行 \(a,b,c\) 等若干个任意类型的输出。此函数不存在取地址问题,可以放心使用。