浅谈程序复杂度的常数优化

如果编译器没有开O2优化
用库函数常数会凭空增加很多。。
似乎NOIP考场不开O2
某些时候,如果你优化到无法再优化的时候
尝试去自己重新实现库函数。

比如

isdigit()
max()/min()
unique()/lower_bound()/upper_bound()
scanf()/printf()
cin/cout
getchar()/putchar()
STL::queue/stack/priority_queue/deque

常数优化:

位运算

没有O2的时候(有O2不用管。编译器会帮你)
x*10 <=> (x<<3)+(x<<1)
x!=y <=> x^y
x!=-1 <=> ~x
x*2 <=> x<<1
x*2+1 <=> x<<1|1
x/2 <=> x>>1
(x+1)%2 <=> x^1
x%2 <=> x&1
x%2==0 <=> ~(x&1)

语法

inline 在非递归函数前加修饰。
循环变量 int i =>register int i

c++没有尾递归优化。所以可以自己手写栈来优化递归。

原则上尽量减少乘/除/取模 指令
取模指令如果是逐渐累加的话,

x+=add;x%=mod;
=> x+=add;x>=mod?x%=mod:1;

A?B:C 好像要比if,else语句快。

memset初始化细节 memset(a,0x3f,sizeof(a));
最后的a[1] = 0x3f3f3f3f
int的极限是 0x7fffffff
还可以~0u
INF有的时候不要刚好赋值到0X7FFFFFFF,如果有2个inf的值相加就会溢出。

乘法溢出。
这个要注意。不要直接全部long long这样慢很多

关于类型转换,一般不用管,编译器会处理。
但是,考试环境有点老?没试过,所以如果有不同类型的话最好在前面显示的强转一下。

赋值>int的话请在数字后加LL

下面的不是绝对,环境不同可能不会出错。

建议平时在编译的时候把编译指令加上 “-ansi”

信息学竞赛的一些注意事项:[有误请指正]

pow()函数请慎用,低版本有的时候会CE。

考场不允许使用“bits/stdc++.h”库,并且使用该库变量名可能不能使用next (C++库里面有个template是next会CE)

请尽力少用黑语法。

二分图匹配避免link做变量名(还有个什么变量名Linux也会CE我突然记不到了..有时其实也可以用“中国式的变量名命名法”这样不会CE。 不推荐这种诡异的风格),Linux环境可能会CE。

少用“math.h”|“cmath”库。因为_x,_y,y1,y2,x1,x2,x0,y0,这类命名有时会CE。

考场严禁使用带下划线的库函数。eg. __gcd()

编程时利用宏可以减少代码量,但是请务必在每个变量里加括号。
eg. #define rep(i,s,t) for(int i=(s);i<=(t);i++)

循环变量for(int i;…;…;)请不要放到全局上。这种常数不会卡。相反会带来很多隐式的错误

如果你不精通指针请少用它。指针的代码很难查错。竞赛里面请避免使用函数指针,多级指针,指针数组这样的语法。

如果可以静态实现,请先考虑静态版本的代码。而不是写动态。(malloc() new)

引用和指针不是一个东西。这个语法我已经不想解释了。去买本语法书细读。

考试少用C++的OOP特性,可以使用STL template<> class namespace 但不推荐使用。

请熟悉STL里面的 string queue stack vector set map 后面这些用的少,仅供参考并且在pascal选手消失前应该是不会考的前面这些只是方便才用,但请注意常数!推荐自己实现。 deque multiset multimap bitset

宏指令少用,#progma 肯定是禁了的,别想手动扩栈。涉及操作编译器和系统的函数都要挂。

内嵌汇编也是算作弊处理,毕竟这是算法竞赛,不是信息安全竞赛,也不是编程能力竞赛。

下面的话来自一位编程大神有可能我记错了或者大神说错了..
然后有的童鞋认为memset()既然这么容易错,那为什么我们还要用呢,直接for一遍初始化。请注意,memset()底层是用汇编实现的效率要比直接的快4倍,不是所有的库函数都是c\c++实现的。
(我记错了吗..还是strlen() 记不到了QAQ,但是memset实现应该不是直接for,肯定有很多常数优化和位运算)

哦,然后就是strlen() 重点! 像下面这种代码复杂度是o(nL)的,L为str的长度。
for(int i=0;i < strlen(str);i++
已经有很多人还是写的上面的这种代码却一直不知情。等你被卡了就知道了。

最后还有一个问题。由于没有开O2优化,会导致一些本来没有区别的变得比较明显。多维数组请把大的放前面。eg. int dp[10000][10][2] 而不是 dp[2][10][10000],常数差距0.5s。比算法的差距还大。开了o2后差别不明显。

还有一个坑。那些将cin/cout和scanf()/printf()一起用的朋友们,如果你们的代码再怎么查都查不出错了,这个时候要考虑是不是把c++和c的IO函数混用了。这个会导致一些潜在性的问题。尤其是当你用了iOS::sync_with_stdio(false); 后。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值