Kitamasa 算法 总结
Kitamasa 算法 总结
Kitamasa 算法,名字来源(?):https://codeforces.com/topic/149912/en9。
推荐阅读:https://zhuanlan.zhihu.com/p/1964051212304364939。
这个算法用于 \(O(k^2 \log n)\) 计算常系数齐次线性递推的第 \(n\) 项,即求以下递推式的第 \(n\) 项:
其中 \(A,c\) 都为常数。
主要思想是,类似快速幂的,拆成若干 \(f(2^i)\),然后想办法把它们拼起来。
首先 \(f(n)\) 一定能表示成 $\sum _{i=0}^{k-1}b_iA_i $ 的形式,\(b_i\) 即初始第 \(i\) 项的贡献系数。
假如我们已经求出 \(f(n)=\sum _{i=0}^{k-1} a_i A_i\),\(f(m)=\sum _{i=0}^{k-1} b_iA_i\),如何求出 \(f(n+m)\)。
由于 \(f\) 的转移平移后还是成立的,所以(平移 \(m\) 位):
只需要快速算出 \(f(m),f(m+1),f(m+2),\dots\) 的系数即可 \(O(k^2)\) 得到 \(f(n+m)\) 的系数。
考虑每次根据 \(f(m)=\sum _{i=0}^{k-1}b_iA_i\) 求出 \(f(m+1)\) 的系数,根据平移有:
把 \(f(k)\) 用递推式展开并化简最终就可以得到:
于是可以每次 \(O(k)\) 求出下一项 \(f\)。
同时上述得到 \(f(n+m)\) 的算法,就可以每次调用求下一项的函数求出所有 \(f(m),f(m+1),f(m+2),\dots\),最终做到 \(O(k^2)\)。
有了上述两种算法,我们可以做如下快速幂:
- 若 \(n<k\),返回只有 \(b_n=1\) 的系数数组,其他位置都为 \(0\),复杂度 \(O(k)\)。
- 否则:
- 若 \(n\) 为奇数,返回 \(f(n-1)\) 的下一项,递归计算 \(f(n-1)\),再调用求下一项的函数,复杂度 \(O(k)\)。
- 若 \(n\) 为偶数,递归计算 \(f(n/2)\),然后将两个 \(f(n/2)\) 合并,复杂度 \(O(k^2)\)。
总复杂度 \(O(k^2\log n)\)。

浙公网安备 33010602011771号