Kitamasa 算法 总结

Kitamasa 算法 总结

Kitamasa 算法,名字来源(?):https://codeforces.com/topic/149912/en9。

推荐阅读:https://zhuanlan.zhihu.com/p/1964051212304364939。

这个算法用于 \(O(k^2 \log n)\) 计算常系数齐次线性递推的第 \(n\) 项,即求以下递推式的第 \(n\) 项:

\[f(n)=\begin{cases} A_n & 0\le n<k \\ \sum _{i=0}^{k-1} c_if(n-k+i) & n>k \end {cases} \]

其中 \(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(n+m)=\sum _{i=0}^{k-1} a_i f(m+i) \]

只需要快速算出 \(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(m+1)=\sum _{i=0}^{k-1} b_if(i+1) \]

\(f(k)\) 用递推式展开并化简最终就可以得到:

\[f(m+1)=b_{k-1}c_0A_0+\sum _{i=1}^{k-1} (b_{k-1}c_i+b_{i-1})A_i \]

于是可以每次 \(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)\)

例题

posted @ 2026-01-26 22:15  dengchengyu  阅读(27)  评论(0)    收藏  举报