一些优化
快读
以P10815为例。
IO 是这道大数据求和题真正的瓶颈。
数据规模最高到 \(10^8\),直接用 cin 或者 scanf 读数据,很容易卡在输入环节超时。
手写快读是比较直接的解决办法。
IO 性能模型
单次系统调用开销远高于普通算术运算。
读取总耗时
\(T_{syscall}\) 代表系统调用开销,\(T_{copy}\) 是内核向用户空间拷贝数据的耗时,\(T_{parse}\) 负责字符转数字。
快读本质就是降低这三项开销。
思路
利用 fread 一次性把一大段输入拉进用户侧缓冲区,后续所有字符解析都在用户内存完成。
减少频繁进入内核的切换成本。缓冲区大小需要权衡,过小会多次读取,过大占用更多内存。
解析逻辑
遍历缓冲区内字符,跳过空格、换行这类空白分隔符。
遇到负号记录符号,依次读取数字字符并计算数值。
写解析代码时尽量精简分支,减少CPU流水线停顿。解析完成后移动指针,继续处理下一组数字。
code
#include<cstdio>
char buf[1<<25];
int ptr;
inline int read(){
int x=0,f=1;
while(buf[ptr]<'0'||buf[ptr]>'9'){
if(buf[ptr]=='-')f=-1;
ptr++;
}
while(buf[ptr]>='0'&&buf[ptr]<='9'){
x=x*10+buf[ptr]-'0';
ptr++;
}
return x*f;
}
int main(){
fread(buf,1,sizeof(buf),stdin);
ptr=0;
int n=read();
long long sum=0;
for(int i=1;i<=n;i++)sum+=read();
printf("%lld\n",sum);
return 4352;//🤪
}
编译优化
编译时开启 O2。
inline 函数会被内联,省去函数调用开销。
编译器会简化循环与分支,减少指令周期。
O2不会改动程序逻辑,不会破坏读入正确性。
其他
关闭同步的 cin 速度会提升,但上限不如整块缓冲快读。
scanf自带缓冲,但封装逻辑重,亿级数据下速度不足。
getchar 逐字符读取,依赖库缓冲,调用次数更多,性能弱于 fread 整块读取。
内存与缓冲区
大容量缓冲区不要放在栈里,栈空间有限,容易栈溢出。
全局变量存放在静态区,适合做大缓冲。
缓冲区尺寸选择2的幂次,方便内存对齐,提升访问速度。
边界
这种一次性预读写法,输入总量超过缓冲区容量时,单次 fread 无法读完,需要改成循环填充缓冲区。
输入格式错乱会导致指针偏移,解析结果出错。
流水线与分支优化
解析代码里的条件分支会引发分支预测失败,增加耗时。
调整判断顺序可以提升预测成功率。
无分支写法能够消除分支开销,但可读性变差,调试麻烦。

优化
浙公网安备 33010602011771号