$\newcommand{\O}{\mathrm{O}}$
$k$ 項間線形漸化式の $n$ 番目の値 $a[n]$ を求めるアルゴリズム. 行列累乗を用いると $\O (k^3 \log n)$ の計算量で求めることができるが, 以下の実装ではより高速なきたまさ法を用いて $\O (k^2 \log n)$ で求めている.
このブログが参考になった. 以下では定数項が存在する場合にも対応した実装にしている.
高速に多項式乗算(FFT) と多項式剰余(Montgomery 乗算) を計算することできたまさ法のオーダーを $\O (k \log k \log n)$ に落とせるらしいがよくわかっていない.
時間計算量: $\O (k^2 \log n)$
template<typename T> void rec(const vector<T>& c, vector<T>& res, const long long n, const int k) { if(n < k){ res[k-1-n] = 1; return; } rec(c, res, n/2, k); vector<T> num(k+1, 0), sm(k+1, 0); vector<T> tmp = res; int flag = n % 2; if(!flag) for(int i = 0; i <= k; i++) sm[i] = res[i] * tmp[k-1]; for(int i = 0; i < k - !flag; i++){ for(int j = 0; j <= k-1; j++){ num[j] = res[0] * c[j] + res[j+1]; } num[k-1] = res[0] * c[k-1], num[k] = res[0] * c[k] + res[k]; for(int j = 0; j <= k; j++){ sm[j] += num[j] * tmp[k-2-i+flag], res[j] = num[j]; } } sm[k] += tmp[k]; res = sm; } // solve(c, x) // 第1引数(係数) a[k] = c[0] * a[k-1] + c[1] * a[k-2] + ... + c[k-1] * a[0] + c[k] // 第2引数(初期値) a[0] = x[0], a[1] = x[1], ... , a[k-1] = x[k-1] template<typename T> T solve(vector<T>& c, vector<T>& x, const long long n) { int k = (int)x.size(); vector<T> res(k+1, 0); rec(c, res, n, k); T ans = 0; for(int i = 0; i < k; i++) ans += res[i] * x[k-1-i]; return ans + res[k]; }