可能很多OIER发现算法在实际生活中没什么用(但可以吹牛)。
比方说,在一个有序数列中找一个数。假定数列已经确定(即不考虑读入时存储的时间),在OI中我们常常用二分法,效率为O(logn);然而实际生活中(即不用计算机),我们发现往往直接枚举一遍或是随机化查找,尽管理论上效率是O(n),但比二分查找的人一般要快。这是为什么呢?
经过上百次试验和苦苦的思考,可以发现:这是显然的。计算机计算mid值是O(1),查询某个位置的数也是O(1),然而你手算不一定能达到这个效率;即使达到了mid值快速求解,查询某个位置的数时,你也要枚举一遍找这个数O(mid),因为你事先不知道每个数的位置,这样一来,二分效率就成了O(nlogn)。但是,如果事先把数列中每个数赋一个下标,在n较大时,二分效率应该是更高的。
但是我们也不能因此否认二分法啊,想一想,如果像猜数字那种给你有限次机会,二分法显然是最佳策略,这也间接体现了二分法的高效率。(因为这时复杂度就是猜的次数而不是消耗时间了)
昨天上数学课时,讲了二项式定理在求余数中的应用,即a^k mod b。如果不用二项式定理,学OI的人一眼就看出这是快速幂了。快速幂的时间复杂度为O(logk),而如果直接暴力计算,复杂度是O(k),理论上看,快速幂应该更优。但是同样不给你用计算机而手算的话,暴力计算(即一遍一遍乘过去,最后取mod)在数字较小时有时反而更快。其实原因也不难想,取mod在计算机看来复杂度是O(1),而对于我们就不是了。手算时列竖式除法,复杂度为O(n),其中n为数字十进制位数。快速幂是边乘边取mod,复杂度就会更高。但如果只求a^k,快速幂又显然更快了。
但是我们又会发现,即使忽略求余数时的时间复杂度,无论是暴力还是快速幂,总不可能降到理论复杂度。其实原因也不难想,我们计算时采取列竖式计算,而在64位整数范围内计算机乘法运算却可以达到O(1)复杂度,这显然是竖式计算达不到的(当然我们讨论的是结果在64位整数范围内的乘法,否则不可能手算:会头破血流)。竖式计算相当于计算机计算时用高精度计算,这时复杂度已不是O(1),而是O(n^2),其中n为数字十进制位数。故快速幂的总时间复杂度为O((lg(a)+lg(a)^2)*log(k)),暴力的复杂度为O(lg(a^k)+lg(a^k)*lg(a^k)*k),数据小时暴力较快。
当然,上面一切一切都还是进行了很多简化。事实上,你手算中进行算法的逻辑判断等等,总比无脑算要耗掉更多时间。