P10815 【模板】快速读入 题解
KobeBeanBryantCox · · 题解
P10815 【模板】快速读入 题解
题目传送门。
题目好评!
这篇题解讲一下快读的原理,顺便讲一下快输的原理。
update on 2025-2-3:更新了原理,之前的原理是有问题的(感谢 @LionBlaze 大佬)。
update on 2025-6-28:被这个 Hack 了,真恶心,改了一下。
快读
我们都知道
getchar的速度快于普通的cin或者scanf(原因放在了最后),于是我们考虑能不能使用getchar读入字符代替数字。众所周知,每个可见字符都有其对应的 ASCII 码编号,那我们就考虑使用字符的编号与数字进行联系。
上面两句其实是废话。
这显然可以做到。
于是我们就按照顺序读入数字。
我们应该先读入掉前面没用的字符,比如空格之类的。
同时应该注意如果读入减号,我们应该打一个标记表示这个数字是负数。
char c=getchar();
while(c<'0'||c>'9') // 非数字的过滤掉
{
if(c=='-')f=-1; // 标记是负数
c=getchar();
}
然后再读入数字,从高位到地位,每次读入一个个位数,我们应该把原来已经读入好的乘
举个例子,读入了
这个应该都能理解吧,如果理解不了,可以想想小学做竖式计算的过程和这个有什么联系。
while(c>='0'&&c<='9')k=k*10+c-'0',c=getchar(); // 注意是数字才读入,然后 c-'0' 的意思是找到 c 对应的个位数
总快读代码:
int in()
{
int k=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9')k=k*10+c-'0',c=getchar();
return k*f; // 别忘记标记的负数要乘进去
}
// 调用时用 n=in();
快输
由快读同理可得,我们能使用 putchar 代替普通输出。
由于按位输出,从高到低,不好操作,这里采用递归的形式。
不知道递归的读者出门右转,度娘在等您。
先处理负数。
if(x<0)putchar('-'),x=-x;
然后分类讨论。
- 小于
10 ,代表是个位数,直接输出数字对应的字符:
if(x<10)putchar(x+'0');
- 大于等于
10 ,这个时候应该先递归输出高位,再输出低位。
else out(x/10),putchar(x%10+'0');
其中 x/10 是去掉个位后的 x%10 是取出
总快输代码:
void out(int x)
{
if(x<0)putchar('-'),x=-x;
if(x<10)putchar(x+'0');
else out(x/10),putchar(x%10+'0');
}
// 直接调用 out(n) 就行了
本题 AC 代码
注意一下本题卡常,要用 getchar_unlocked,原理跟 getchar 差不多,只不过更快一点。
不过不建议平时写题用这个,因为有些编译器会报错。
update on 2025-6-28:被卡 int 了,全部改成 long long 就能过了。
#include<bits/stdc++.h>
#define Code using
#define by namespace
#define wjb std
Code by wjb; // 至于这个是什么,咳咳,我不说
#define int long long
int in()
{
int k=0,f=1;
char c=getchar_unlocked();
while(c<'0'||c>'9')
{
if(c=='-')f=-1;
c=getchar_unlocked();
}
while(c>='0'&&c<='9')k=k*10+c-'0',c=getchar_unlocked();
return k*f;
}
void out(int x)
{
if(x<0)putchar('-'),x=-x;
if(x<10)putchar(x+'0');
else out(x/10),putchar(x%10+'0');
}
signed main()
{
int n=in(),sum=0;
while(n--)sum+=in();
out(sum);
return 0;
}
快读快输比正常输入输出快的原因
update on 2025-2-3:将此段不合理的表述删去,加入正确的内容。
cin 和 cout 的特点
- 同步流:
cin和cout与 C 语言的标准输入输出流(stdin和stdout)是同步的。这种同步机制保证了在混合使用 C++ 的cin/cout和 C 的scanf/printf时不会出现输入输出混乱的情况。但同步操作会带来额外的开销,因为每次进行输入输出操作时,都需要进行一些同步检查和处理,这会降低输入输出的效率。我们常说的关闭同步流就是在这里进行加速。 - 格式化处理:
cin和cout支持丰富的格式化输入输出功能,例如可以方便地处理不同类型的数据(如整数、浮点数、字符串等),并且可以通过setw、setprecision等操纵符进行格式化设置。然而,这些格式化处理需要进行复杂的类型检查和转换,会消耗较多的时间。(注:@LionBlaze 大佬说cout是调用了sprintf这个比较慢的函数,不过正确性未知。)
scanf 和 printf 的特点
- 格式化解析:
scanf和printf是 C 语言中的输入输出函数,它们也需要进行格式化解析。例如,scanf("%d", &num)需要解析格式字符串%d,并根据该格式从输入中读取相应的数据。这种格式化解析过程会带来一定的开销,尤其是在处理大量数据时,开销会更加明显。
不过上面这一段我觉得一点用都没有,快读快输比正常读入输入快这一条性质背下来就行了啊 QAQ。
后记
如果有什么写的不好或者错误的地方,欢迎评论指出!