一次TLE的教训
在CF上刷题的时候,遇到一道数据很大的题。
https://codeforces.com/edu/course/2/lesson/2/3/practice/contest/269118/problem/B
n可以取到3e5,我用O(N*log(N))完全能过的,但是…
我不理解,刚开始我以为是有个特例让我二分死循环了,然后我对拍了无数次,跑的都挺快的,我试着限制二分次数break掉,还是TLE,这说明是程序复杂了。尝试了很多种办法,比如记忆化,更快的快读,不开long long等…
后来在讨论里看到也有人TLE了,下面有人评论说,比较的compare函数要自己写,这时我突然想到,在二分里如果check不是O(1)的话,复杂度确实会非常可怕,我试着自己写了个compare,但还是TLE,不过它提供了一个思路,那就是减少大循环里的一些很复杂的函数,比如strlen,size(),等,它们其实都是O(N)的。
我在循环里去掉它们,并写到循环的外面之后,时间确实节省了不少,因此就AC了。
其实compare只能节省一点点的时间,毕竟都是O(N)的.
继续按照这样的思路优化,我把函数的形式参数都去掉,都放到全局区,提交上去之后,我大受震惊。
这也太快了吧,函数参数以值传递确实会有开销,但我没想到影响这么大。。。
我又试了一次传引用,突然就真相大白了,时间也是非常的短。
string好歹也是c++里的一个类,作为参数传递的时候调用构造函数赋值过去,函数结束之后又会调用析构函数,确实开销很大。
所以,对于数据大的题目如果TLE,如果算法本身没问题,试着这样去优化:
循环里少放strlen,size() 等复杂度大的函数,在不修改对象的情况下,函数参数尽量传的是引用(其实指针也行)。
还有一些经验性的结论:数据没爆的话关掉long long可能就过了。一般关了同步的cin是够用的而不必快读(除非那种黑题)。换个编译器可能就过了,比如poj上的g++TLE了,改用C++就能过。