首先声明,本博文部分内容仅仅适用于ACM竞赛,并不适用于NOIP与OI竞赛,违规使用可能会遭竞赛处理,请慎重使用!遭遇任何情况都与本人无关哈=7=
我也不想搞得那么严肃的,但真的有些函数在NOIP与OI竞赛中有相关规定不能使用,详细我也不知道各位要了解请自行去找比赛要求咯,当然在ACM竞赛中,没有限制函数,所以所有内容都适用于ACM竞赛。
那么什么是卡常数呢,简单来说就是你和某神犇算法思路一样,结果他的AC了,你的TLE,复杂来说就是程序被卡常数,一般指程序虽然渐进复杂度可以接受,但是由于实现/算法本身的时间常数因子较大,使得无法在OI/ACM等算法竞赛规定的时限内运行结束。
下面就是介绍各种各样的非(花)常(里)实(胡)用(哨)的优化方法的,若本文某些地方有错误或不明确的地方还请指出。=7=
优化I/O
网上有很多说关于cin和scanf的介绍,以及关闭流输入等等优化方法,但这些都还是有可能成为卡常数的地方,那么这个时候,我们就可以自己写输出输出函数了。
下面一个简单的对读入数字的优化:
1 inline void read(int &sum) { 2 char ch = getchar(); 3 int tf = 0; 4 sum = 0; 5 while((ch < '0' || ch > '9') && (ch != '-')) ch = getchar(); 6 tf = ((ch == '-') && (ch = getchar())); 7 while(ch >= '0' && ch <= '9') sum = sum * 10+ (ch - 48), ch = getchar(); 8 (tf) && (sum =- sum); 9 }
因为getchar()是比scanf和cin快很多的,所以可以用这种方式优化很多,当然也可以写对其他各种类型输入的优化。
然后就是进阶版优化,cstdio库里面有一个非常快而且和freopen和fopen完美兼容的函数就是fread,而且是整段读取,函数原型为:
1 size_t fread(void *buffer,size_t size,size_t count,FILE *stream);
作用:从stream中读取count个大小为size个字节的数据,放到数组buffer中,返回成功了多少个大小为为size个字节的数据。
所以我们的代码可以更加优化为:
1 inline char nc() { 2 static char buf[1000000], *p1 = buf, *p2 = buf; 3 return p1 == p2 && (p2 = (p1 = buf) + fread (buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++; 4 } 5 6 //#define nc getchar 7 inline void read(int &sum) { 8 char ch = nc(); 9 int tf = 0; 10 sum = 0; 11 while((ch < '0' || ch > '9') && (ch != '-')) ch = nc(); 12 tf = ((ch == '-') && (ch = nc())); 13 while(ch >= '0' && ch <= '9') sum = sum * 10+ (ch - 48), ch = nc(); 14 (tf) && (sum =- sum); 15 }