严格来说,这可能并不能算作学习笔记,但还是这么算了。
这篇文章可能全程比较沙雕,所以对于风格不要过度在意。
咳咳,上面都是作者的废话。下面进入正题。
这篇文章主要介绍的是一些比较常用(?)的 OI 小技巧。这可能有助于在 OI 中获得优势(?( imes 2))。
文章内容按照字典序排序。
( extrm{I}). 龟速乘
这是一个极其常用的小技巧,原因比较简单,那就是比赛时常用。
通常来说,一道题的答案如果过大的话,有两种方案——高精度和取模。
但是,由于前一段时间(?( imes 3))的接连不断的高精度把人弄得有一点烦,加上高精度本身也有复杂度一说,所以并不是一个理想的评测算法的工具。
取而代之,很多题目都会在题目末尾加上一句「答案对 (998244353) 取模」或类似的话。一来是解决内置变量存储上限,二来则是忽略计算复杂度。
但是,当模数极其接近变量上限边缘时,乘法就变得岌岌可危,比如:计算 (123456789876 imes 5432123456789 mod{192837465647389}) 这种类似的东西。
咳咳,于是乎,我们就发明了一种很棒的东西。这可以解决模数上限的问题,但不可避免地会出现一点常数,虽然只有 (O(log n))。这就是龟速乘。
那说了这么多,龟速乘到底是个什么东西呢?????说白了就是快速幂。为什么?
多次连乘是乘方运算,多次连加就是乘法运算
也就是说吧乘法变成一次次的加法而达到其目的,也就不可避免地有 (O(log n)) 的多余复杂度。
但是!这并不是唯一的解决办法,网上还有通过 long double 来卡精度从而达到 (O(1)) 的龟速乘,这里不再赘述。
( extrm{II}). 快速幂
快速幂是位运算的应用中的一种,可以在 (O(log n)) 的时间内计算形如 (a^b (bin mathbb{N}^{*})) 的算法。
简单来说,就是计算一个数列 (left<c_0,c_1,c_2,cdots,c_k ight>),使得 (b=sumlimits_{i=0}^k left(c_i imes 2^i ight)),这可以通过二进制分解在 (O(log n)) 的时间内解决。
接下来是算法的精髓——注意到 (2^i=2^{i-1} + 2^{i-1}),即 (u^{2^i}=left(u^{2^{i-1}} ight)^2)。
( hereforequad a^b=prodlimits_{i=0}^k a^{2^i})
而预处理 (a^{2^i}) 是 (O(k)sim O(log n)),总体就是 (O(log n))