最近颓得要命,于是写篇玄学论文扯淡聊以自慰
1、IO优化
读入优化
cin
慢得可以,比赛用这个其实就是自寻死路
scanf
比较慢,比赛多用的还是下面两种读入方法
getchar读入优化
inline int read()
{
char ch;
int x = 0, f = 1;
while ((ch = getchar()) < 48 || ch > 57)
if (c == '-') f = -1;
while (ch >= 48 && ch >= 57)
x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
return x * f;
}
一般getchar足够应付不刁钻的题目,可是最近NOIP真的卡常卡得毒瘤至极,这时我们帅气的fread就闪亮登场了:
char ibuf[500 << 20] , * s;
struct io
{
io()
{
fread(s = ibuf, 1, 500 << 20, stdin);
}
inline int read()
{
register int u = 0;
while (* s < 48 || * s > 57) s ++;
while (* s >= 48 && * s <= 57)
u = u * 10 + * s ++ - 48;
return u;
}
} ip;
调用时介样调用:x = ip.read()
如果在本地运行并且使用了fread,那么请在输入结束后按回车键,再按Ctrl+z,再按回车键结束输入
看不懂没关系,能默写就行
简单地解释一下代码:
io结构体中有一个同名函数,创建结构体时将默认调用它;
*s是一个指针,它始终指向ibuf数组的一个位置;
fread函数第一个参数是读取地数据存放的场所(原型里是一个指针,但不用管这些),第二个参数是每次读取的字节数,我们想每次读入一个字符存到ibuf里;
那么一个字符是一个字节大小的,所以在这里一般都写1;
那么fread函数每读入一个字节后,传入的指针(这里是ibuf,并“顺便”把s指针赋值为ibuf数组的首地址)都会后移一位;
第三个是最多读取的字节,把它设置为一个很大的值就行了,不用管其他的;
第四个参数是你要从哪里读入数据,在这里是标准输入流(stdin),默认是键盘,也可以重定向(freopen)把标准输入流改为某个文件;
看不懂很正常,没关系,会默写就OK
scanf只比cin快一点,getchar比scanf快很多,fread比getchar快很多
输出优化
cout
强烈不推荐使用
printf
可以使用
putchar优化
推荐使用,代码就不给出了,比较好写
puts
能用puts就用puts,要输出数字用putchar或者printf或者下面介绍的fwrite即可
fwrite
在这里不解释代码,会指针都看得懂,fwrite函数格式和fread差不多的。
inline void print(register int u)
{
char obuf[105], *s = obuf;
register int x = 1;
while (x <= u) x *= 10;
x /= 10;
while (x) *s ++ = u / x + 48, u -= u / x * x, x /= 10;
fwrite(obuf, 1, s - obuf, stdout);
}
ps:虽然输出大量数据时fwrite速度远超其他方法,但输出量较少时比puts稍慢。在有些OJ上可能fwrite还不如putchar,但在OI中fwrite绝对是最快的
输入输出量越大,各种方式差距的比例也越大。开始可能getchar和fread速度完全一样,可是数据大了(比如一亿个)那fread速度就是getchar的几十倍了……
不过一般输出量很少,所以输出优化意义不大,但是也有输出量特别多的
OI中最快的输出写法:
输出单个字符putchar,字符串puts,数字fwrite输出
2、inline,register,define超级玄学优化
register一般没什么用,格式:register 类型名 变量名;
在声明函数前加个inline,可减少跳转和传参的代价,比register有用点(详见上面的fread的read函数)
在dfs或其他需要多次递归调用函数的时候,inline不可不加,上次我某道题在dfs时不加inline70分,加了就80分了……
define就是一个替换,用它来代替函数可以去掉跳转和传参的代价,但是注意define别爆炸,一般还是用inline稳妥一些
3、数组优化
把数组开小,把int的数组能改成char就改成char,会提高程序效率。
在数组大小达到一百万以上时,访问速度会比较的慢
4、去STL
手写,因为STL常数特别高。。。
STL的除了set其余的容器和算法大家应该都会手写吧……
5、去指针优化
比如说一个最短路,明明可以邻接链表和vector存,你非要指针形式……
常数*100000000
6、卡时优化
比如for循环只for几次,比如dfs递归到几次或者几层就直接return,比如SPFA某个点入队了100次就坚信这个图有负环……
总之,这个技巧使用乱搞恰当的话,可以让你本来就能AC的点继续AC,TLE的点多AC几个点
技巧原理:宁愿WA也不愿意TLE
例:
有一次一道最短路有负权还卡SPFA,加了SLF还超时,全班统一做法:某个点进队200次直接判负环,inline + register,deque换成手写队列
就AC了……
各种玄学的比较
效果方面:
1、卡时优化
2、去指针优化
3、去STL优化
4、数组开小优化
5、读入优化
6、inline,register,define
风险方面:
1、卡时优化
2、去STL优化
3、数组开小优化
4、读入优化
5、去指针优化
6、inline,register,define
后三个差不多没有任何风险
共 12 条回复
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%