经常有人问我要我的头文件板子于是我就打算来水一篇文章了。

快读快写

因为快读快写是针对某个类型特别设计的,所以如果没有使用对应的读写函数但是依然使用readwrite进行读写的话会产生错误!

普通的scanfprintf打比赛其实已经够了,但是平常为了 装逼 写得方便,因为scanfprintf实在是太长了,就还是用了快读。而且从某种意义上scanfprintf因为太万能了所以也会比快读快写慢那么一丢丢。而且__int128的读入和输出不是也必须要用快读快输么(理直气壮)。

整数

快读

整数快读的原理就是把读数字变成读字符,用getchar读字符非常快。

下面这个是快读板子,支持intlonglong,用的时候就直接read(n);即可,非常方便。

read(n);scanf("%d", &n);scanf("%lld", &n);相同作用。不用担心类型不适配,他是个成熟的快读了,会自动适配的。

1
2
3
4
5
6
7
template <typename T>inline void read(T& x){
T sum = 0, f = 1;
char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
x=sum*f;
}

快写

快写和快读是一个原理,快读是把读数字变成读字符,快写就是把写数字变成写字符,putchar就很快了。

使用的时候直接write(x);即可。

write(x);printf("%d", x);scanf("%lld", x);相同作用。不用担心不适配,他是个成熟的快输了,会自动适配的。

1
2
3
4
5
template<typename T> inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}

小数

因为ACM小数一般用的是double,因此默认小数定义为double,定义float使用小数快读快写可能会出错。

但是问题来了,有整数,小数怎么办?只有整数没有小数这也太不优雅了,而且也没办法摆脱scanf。

快读

小数比整数麻烦一些,因为有整数部分和小数部分,那么就分成两部分来读,然后拼起来就可以了。

使用时直接read(x);即可。

使用了板子后:read(x);scanf("%lf", &x);相同作用。

1
2
3
4
5
6
7
8
inline void read(double &x){
double z=0,t=0;int s=0,f=1;char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1; if(c=='.') goto readt; c=getchar();}
while (isdigit(c)&&c!='.') {z=z*10+c-'0';c=getchar();}
readt:while (c=='.') c=getchar();
while (isdigit(c)) {t=t*10+c-'0';++s; c=getchar();}
x=(z+t/pow(10,s))*f;
}

快写

快写比快读麻烦很多,也是把小数分成整数和小数两部分,整数部分直接用整数快写就行,小数部分自己动手丰衣足食。另外还要考虑保留几位小数和四舍五入的问题。

下面这个是我参照其他大佬写的然后自己改改实现的小数快写。默认是保留六位小数,四舍五入。

使用时如果默认是保留六位小数那么直接write(x);即可。如果需要保留特殊小数位数,需要多一个参数write(x, k);,k为保留位数。

使用了板子后:write(x);printf("%lf", x);相同作用。write(x, k);printf("%.(k)lf", x);相同作用,注意k为参数。另外保守起见最好最多只保留到小数后16位。

1
2
3
4
5
6
7
8
9
10
11
12
13
inline void write(double x,int k=6){
ll n=pow(10,k + 1);
if (x==0) {putchar('0'),putchar('.');for (int i=1;i<=k;++i) putchar('0');return;}
if (x<0) putchar('-'),x=-x;
ll y=(ll)(x*n)%n;x=(ll)x;
int bit[20], p=0,i;
if(y % 10 >= 5) y = y/10+1;
else y = y/10;
for (;p<k;y/=10) bit[++p]=y%10;
if(y) x++;
write((ll)x),putchar('.');
for (i=p;i>0;i--) putchar(bit[i]+48);
}

字符串

整数,小数,再来个字符串就完美起来了,字符串肯定是string香啦,但是string是要配合cin读入的,cin不解绑的话就很慢了,于是字符串快读来了。

快读

使用时直接read(x);readline(x);即可。

使用了板子后:read(x);cin>>x;相同作用。

1
2
3
4
5
6
inline void read(string& x){
x="";
char ch=getchar();
while(ch==' ' || ch=='\n' || ch=='\r')ch=getchar();
while(ch!=' ' && ch!='\n' && ch!='\r') {x+=ch;ch=getchar();}
}

这样的话就可以实现字符串的快读了,另外可以注意,如果需要读取一行的话,只需要将第二个while里面的ch!=' '删掉就好。

使用了板子后:readline(x);cin.getline(x,maxsize);相同作用,有点类似于gets(x);

1
2
3
4
5
6
inline void readline(string& x){
x="";
char ch=getchar();
while(ch==' ' || ch=='\n' || ch=='\r')ch=getchar();
while(ch!='\n' && ch!='\r') {x+=ch;ch=getchar();}
}

快写

使用板子后:write(x);cout<<x;作用相同。

1
2
3
inline void write(string x){
for(int i=0; x[i]!='\0'; i++) putchar(x[i]);
}

使用时直接write(x);即可。


多参数

快读

欸嘿,有了快读板子就快了起来了,但是我发现如果要读多个的话就要read(x);read(y);,这太傻逼了,还没有scanf快,如果能直接read(x, y);多好,于是有了下面这个配合read实现多参数读入的。加上了之后用的时候直接read(x, y...);即可。

1
2
3
template <typename T,typename... Args> inline void read(T& t, Args&... args){
read(t);read(args...);
}

快写

快写与快读不同,因为不能单纯的快写,中间往往有空格,换行或其他字符。所以需要一个辅助输出字符。

1
2
3
4
5
6
7
8
template <typename T> inline void write(const char ch, T x){
write(x);putchar(ch);
}

template <typename T, typename... Args> inline void write(const char ch, T x, Args... args){
write(ch, x);
write(ch, args...);
}

使用方法也与多参数快读不同,第一个参数为输出之间的字符,然后后面的依次为输出的参数。

例如:

write('\n', a, b, c, ...);printf("%d\n%d\n%d\n",a, b, c);相同作用。

write(' ', a, b, c, ...);printf("%d %d %d ", a, b, c);相同作用。注意行末有空格。

因为快写设计原因,也可以实现写了就换行,write('\n', x);,这样就和printf("%d\n", x);相同作用。

值得注意的是小数的特殊位数多参数快写这个不能适用,字符串读取一行的也不能,其他的都可以添加上上面两个后实现多参数快读快写。


快读快写大礼包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//---------------------------------------------------//
template <typename T>inline void read(T& x){
T sum = 0, f = 1;
char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
x=sum*f;
}

inline void read(double &x){
double z=0,t=0;int s=0,f=1;char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1; if(c=='.') goto readt; c=getchar();}
while (isdigit(c)&&c!='.') {z=z*10+c-'0';c=getchar();}
readt:while (c=='.') c=getchar();
while (isdigit(c)) {t=t*10+c-'0';++s; c=getchar();}
x=(z+t/pow(10,s))*f;
}

inline void read(string& x){
x="";
char ch=getchar();
while(ch==' ' || ch=='\n' || ch=='\r')ch=getchar();
while(ch!=' ' && ch!='\n' && ch!='\r') x+=ch,ch=getchar();
}

inline void readline(string& x){
x="";
char ch=getchar();
while(ch==' ' || ch=='\n' || ch=='\r')ch=getchar();
while(ch!='\n' && ch!='\r') x+=ch,ch=getchar();
}

template <typename T,typename... Args> inline void read(T& t, Args&... args){
read(t);read(args...);
}

template<typename T> inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}

inline void write(double x,int k=6){
ll n=pow(10,k + 1);
if (x==0) {putchar('0'),putchar('.');for (int i=1;i<=k;++i) putchar('0');return;}
if (x<0) putchar('-'),x=-x;
ll y=(ll)(x*n)%n;x=(ll)x;
int bit[20], p=0,i;
if(y % 10 >= 5) y = y/10+1;
else y = y/10;
for (;p<k;y/=10) bit[++p]=y%10;
if(y) x++;
write((ll)x),putchar('.');
for (i=p;i>0;i--) putchar(bit[i]+48);
}

inline void write(string x){
for(int i=0; x[i]!='\0'; i++) putchar(x[i]);
}

template <typename T> inline void write(const char ch, T x){
write(x);putchar(ch);
}

template <typename T, typename... Args> inline void write(const char ch, T x, Args... args){
write(ch, x);
write(ch, args...);
}
//_____________________________________________________//

头文件板子

板子

下面是我平常打cf刷题的时候用的板子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <list>
#include <set>
#include <unordered_set>
#include <deque>
#include <vector>
#include <ctime>
#include <cctype>
#include <ctime>

using namespace std;
#define ll long long
#define INF 0x3f
#define lowbit(x) ((x) & (-x))
typedef pair<int, int> PII;

//---------------------------------------------------//
template <typename T>inline void read(T& x){
T sum = 0, f = 1;
char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {sum=sum*10+c-'0';c=getchar();}
x=sum*f;
}

inline void read(double &x){
double z=0,t=0;int s=0,f=1;char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-1; if(c=='.') goto readt; c=getchar();}
while (isdigit(c)&&c!='.') {z=z*10+c-'0';c=getchar();}
readt:while (c=='.') c=getchar();
while (isdigit(c)) {t=t*10+c-'0';++s; c=getchar();}
x=(z+t/pow(10,s))*f;
}

inline void read(string& x){
x="";
char ch=getchar();
while(ch==' ' || ch=='\n' || ch=='\r')ch=getchar();
while(ch!=' ' && ch!='\n' && ch!='\r') x+=ch,ch=getchar();
}

inline void readline(string& x){
x="";
char ch=getchar();
while(ch==' ' || ch=='\n' || ch=='\r')ch=getchar();
while(ch!='\n' && ch!='\r') x+=ch,ch=getchar();
}

template <typename T,typename... Args> inline void read(T& t, Args&... args){
read(t);read(args...);
}

template<typename T> inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}

inline void write(double x,int k=6){
ll n=pow(10,k + 1);
if (x==0) {putchar('0'),putchar('.');for (int i=1;i<=k;++i) putchar('0');return;}
if (x<0) putchar('-'),x=-x;
ll y=(ll)(x*n)%n;x=(ll)x;
int bit[20], p=0,i;
if(y % 10 >= 5) y = y/10+1;
else y = y/10;
for (;p<k;y/=10) bit[++p]=y%10;
if(y) x++;
write((ll)x),putchar('.');
for (i=p;i>0;i--) putchar(bit[i]+48);
}

inline void write(string x){
for(int i=0; x[i]!='\0'; i++) putchar(x[i]);
}

template <typename T> inline void write(const char ch, T x){
write(x);putchar(ch);
}

template <typename T, typename... Args> inline void write(const char ch, T x, Args... args){
write(ch, x);
write(ch, args...);
}
//_____________________________________________________//

const int mod = 1e9+7;
const int Count = 10;
const int N = 2e5+5;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+5;
const int charSum = 28;
const double pi = acos(-1);
const double eps = 1e-6;
const int NTT_mod = 998244353;

//_____________________________________________________//

void solve(void){

}
signed main(void){

freopen("in.txt","r",stdin);

solve();

return 0;
}

将头文件板子与vscode相融合

板子好了,但是问题又来了,如果每次打比赛都要拿板子去粘贴这就太不优雅了。如果能按两个键板子就自己跳出来那么多舒服。

你已经是个成熟的板子了,该学会自己跳出来了。

vscode有个用户自定义代码,我们或许可以利用这个来实现一键出板子。

首先设置->用户代码片段

然后在弹出来的搜索框里面输入cpp,点击cpp.json

接下来会弹出一个json文件,用下面的代码替换内部代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
{
"ACM":{
"prefix": "ACM", //关键字,在cpp文件里面输入之后出现
"body": [
"#include <iostream>",
"#include <cstdio>",
"#include <cmath>",
"#include <cstring>",
"#include <algorithm>",
"#include <cstdlib>",
"#include <string>",
"#include <queue>",
"#include <map>",
"#include <stack>",
"#include <list>",
"#include <set>",
"#include <unordered_set>",
"#include <deque>",
"#include <vector>",
"#include <ctime>",
"#include <cctype>",
"#include <ctime>",
"",
"using namespace std;",
"#define ll long long",
"#define INF 0x3f",
"#define lowbit(x) ((x) & (-x))",
"typedef pair<int, int> PII;",
"",
"//---------------------------------------------------//",
"template <typename T>inline void read(T& x){",
" T sum = 0, f = 1;",
" char c=getchar();",
" while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}",
" while(isdigit(c)) {sum=sum*10+c-'0';c=getchar();}",
" x=sum*f;",
"}",
"",
"inline void read(double &x){",
" double z=0,t=0;int s=0,f=1;char c=getchar();",
" while (!isdigit(c)) {if (c=='-') f=-1; if(c=='.') goto readt; c=getchar();}",
" while (isdigit(c)&&c!='.') {z=z*10+c-'0';c=getchar();}",
" readt:while (c=='.') c=getchar(); ",
" while (isdigit(c)) {t=t*10+c-'0';++s; c=getchar();}",
" x=(z+t/pow(10,s))*f;",
"}",
"",
"inline void read(string& x){",
" x=\"\";",
" char ch=getchar();",
" while(ch==' ' || ch=='\\n' || ch=='\\r')ch=getchar(); ",
" while(ch!=' ' && ch!='\\n' && ch!='\\r') x+=ch,ch=getchar();",
"}",
"",
"inline void readline(string& x){",
" x=\"\";",
" char ch=getchar();",
" while(ch==' ' || ch=='\\n' || ch=='\\r')ch=getchar(); ",
" while(ch!='\\n' && ch!='\\r') x+=ch,ch=getchar();",
"}",
"",
"template <typename T,typename... Args> inline void read(T& t, Args&... args){",
" read(t);read(args...);",
"}",
"",
"template<typename T> inline void write(T x){",
" if(x<0) putchar('-'),x=-x;",
" if(x>9) write(x/10);",
" putchar(x%10+'0');",
"}",
"",
"inline void write(double x,int k=6){",
" ll n=pow(10,k + 1);",
" if (x==0) {putchar('0'),putchar('.');for (int i=1;i<=k;++i) putchar('0');return;}",
" if (x<0) putchar('-'),x=-x;",
" ll y=(ll)(x*n)%n;x=(ll)x;",
" int bit[20], p=0,i;",
" if(y % 10 >= 5) y = y/10+1;",
" else y = y/10;",
" for (;p<k;y/=10) bit[++p]=y%10;",
" if(y) x++;",
" write((ll)x),putchar('.');",
" for (i=p;i>0;i--) putchar(bit[i]+48);",
"}",
"",
"inline void write(string x){",
" for(int i=0; x[i]!='\\0'; i++) putchar(x[i]);",
"}",
"",
"template <typename T> inline void write(const char ch, T x){",
" write(x);putchar(ch);",
"}",
"",
"template <typename T, typename... Args> inline void write(const char ch, T x, Args... args){",
" write(ch, x);",
" write(ch, args...);",
"}",
"//_____________________________________________________//",
"",
"const int mod = 1e9+7;",
"const int Count = 10;",
"const int N = 2e5+5;",
"const int inf = 0x3f3f3f3f; ",
"const int maxn = 1e5+5; ",
"const int charSum = 28;",
"const double pi = acos(-1);",
"const double eps = 1e-6;",
"const int NTT_mod = 998244353;",
"",
"//_____________________________________________________//",
"",
"void solve(void){",
" $0", //表示光标默认位置
"}",
"signed main(void){ ",
"",
" freopen(\"in.txt\",\"r\",stdin);",
"",
" solve();",
"",
" return 0;",
"}",
],
"description": "Acm template." //模板描述
}
}

然后保存即可安心食用。

接下来只需要在cpp文件里面输入ACM三个字母,然后优雅的按一下Enter或者tab,便可以欣赏周围人的对你传来的惊讶声了。


如何使用头文件板子

首先在与源代码同一目录下创建一个in.txt文件,此处装载的是源文件的输入。

编译运行之后程序会自动在in.txt中读取数据作为输入,然后在默认窗口输出。

输出结果无误后将下面代码中的freopen语句注释掉。即可Ctrl+A Ctrl+C然后粘贴到onlinejudge提交代码。

pic_5


如何更加优雅的使用头文件板子

可以发现虽然已经很简便,但是在提交代码的时候依然需要注释掉一个语句,不是那么优雅。但是可以通过一些操作。即使不用注释掉这个语句,提交到onlinejudge之后也不运行这个语句,这样就少了一步了,懒人的福音。

首先我们需要知道宏定义代码块

1
2
3
4
#define DEF_NAME //定义宏
#indef DEF_NAME //如果这个宏有被定义,则运行其中语句,否则不运行
...
#endif

那么我们可以用这个来操作一手。

首先gcc/g++ -D _DEBUG命令会自动生成一个对于_DEBUG的宏定义,而在onlinejudge上跑代码是不会含有这个宏定义的,那么我们能够让本地运行的时候多一句gcc/g++ -D _DEBUG,用#ifdef _DEBUG块把freopen语句框起来,这样就可以在本地运行的时候运行freopen,提交之后onlinejudge不运行了。

值得注意的是VS在调试模式中会自动添加_DEBUG的宏定义,就只需要用#ifdef _DEBUGfreopen框起来就可以了。

首先修改cpp.json,在最下方

1
2
3
4
5
6
7
8
9
10
			"signed main(void){ ",
"",
+ "#ifdef _DEBUG",
" freopen(\"in.txt\",\"r\",stdin);",
+ "#endif",
"",
" solve();",
"",
" return 0;",
"}",

增加gcc/g++ -D _DEBUG命令。

此处以vscode做例子,修改.vscode>tasks.json

args中最前面添加

1
"-D _DEBUG",//注意行末的逗号

保存。效果如下图所示。

pic_6

现在就可以在本地运行时运行freopen,提交上去之后不运行freopen了。