OI比赛常数优化
这是一篇玄学文章
一、编译优化
1 #pragma GCC optimize("O3") 2 #pragma G++ optimize("O3")
比赛时除非遇到常数很大可能会卡的暴力题否则一定不要用!玩火自焚!
二、I/O优化
核心:利用getchar()和putchar()这两个底层函数和位运算加速
输入优化(超逼格写法)
1 #include<cstdio> 2 #include<cctype> 3 using namespace std; 4 int read() 5 { 6 int x=0,f=0; 7 char c=getchar(); 8 while(!isdigit(c)) 9 { 10 f|=c=='-'; 11 c=getchar(); 12 } 13 while(isdigit(c)) 14 { 15 x=(x<<3)+(x<<1)+(c^48); 16 c=getchar(); 17 } 18 return f?-x:x; 19 }
这里为什么可以用c^48代替c-48('0')呢?因为48的二进制是110000,后4位均为0,48~57('9')近在后四位后变化,所以^48可以用来代替-48且更快
听说用fread更快但只能写文件,这里就不写代码了,通常比赛时使用上面的优化即可,有兴趣的读者可以查阅资料了解一下
输出优化
每次使用putchar()输出字符可加速输出
实测递归+putchar()输出整数的速度比printf()快6倍!
但不要写递归版……递归版的速度还慢于printf
放上代码
#include<cstdio> #include<cctype> using namespace std; #define re register int int stk[111],tt; void print(int x) { if(x==0) putchar('0'); else { if(x<0) putchar('-'),x=-x; tt=0; while(x) { stk[++tt]=x%10; x/=10; } for(re i=tt;i;i--) putchar(stk[i]|48); } }
格式控制直接手打putchar()即可
stack[i]|48的正确性由输入优化的解释和或运算的定义显然可知
三、寄存器变量
需要大量运算的变量申请为寄存器变量,即register+类型名
通常将循环变量设为寄存器变量
另外将register int设为字符串常量可以简化代码,详见下面代码
1 #define re register int 2 int main() 3 { 4 for(re i=1;i<=999999;i++) 5 return 0; 6 }
不要滥用register,一方面少量变量修改优化效果不明显,另一方面寄存器放不下变量时就会自动把变量放到内存里……
四、取模优化
适用于只有加减运算的题目
int inc(int x,int v,int mod){x+=v;return x>=mod?x-mod:x;}//代替取模+ int dec(int x,int v,int mod){x-=v;return x<0?x+mod:x;}//代替取模-
五、memset,memcpy以及memmove
memset(数组名+第一个操作数下标,0/-1,操作大小*类型所占字节数)
memcpy(目标数组名+该数组第一个操作数下标,被copy数组名+该数组第一个操作数下标,操作大小*类型所占字节数)
memmove(目标数组名+该数组第一个操作数下标,被清空数组名+该数组第一个操作数下标,操作大小*类型所占字节数)
实例:
1 //int是4个字节所以用<<2 2 memset(a+l,0,r-l+1<<2); 3 memcpy(a+l,b+l,r-l+1<<2); 4 memmove(a+l,b+l,r-l+1<<2);
获取类型所占字节数方法:sizeof(类型名)
六、正常的优化
思路:减少运算及比较次数&用位运算代替四则运算
七、程序框架
将register int和long long缩写可以节省时间……用define就行
另外多设一个INF
#include<cstdio> #include<cctype> using namespace std; #define re register int #define ll long long const int INF=0x3f3f3f3f; int stk[111],tt; void print(int x) { if(x==0) putchar('0'); else { if(x<0) putchar('-'),x=-x; tt=0; while(x) { stk[++tt]=x%10; x/=10; } for(re i=tt;i;i--) putchar(stk[i]|48); } } int read() { int x=0,f=0; char c=getchar(); while(!isdigit(c)) { f|=c=='-'; c=getchar(); } while(isdigit(c)) { x=(x<<3)+(x<<1)+(c^48); c=getchar(); } return f?-x:x; } int main() { return 0; }
结束语
此篇文章介绍的优化均已实测证明,下面是一些误传:
- 迷信inline?实测inline还要稍微慢上一丢丢……
- 前置++和后置++实测在单独语句时没有任何差别
- 用三目运算符(?:)代替if()else()?然而实测三目运算符比if()else()还要慢一些……