This documentation is automatically generated by online-judge-tools/verification-helper
#include "src/polynomial/BostanMori.hpp"BontanMori(Q, P, N)$d$ 次多項式 $Q$ 及び高々 $d - 1$ 次の多項式 $P$,整数 $N$.
時間計算量 $\mathrm{O}(d \log d \log N)$
LinearRecurrence(a, c, N)線型漸化式
\[a _ i = \sum _ {j = 1} ^ d c _ j a _{i - j}\]を満たす数列 $a$ の初めの $d$ 項 $a _ 0, \dots , a _ {d - 1}$ 及び係数列 $c _ 1, \dots , c _ d$,整数 $N$.
数列 $a$ の第 $N$ 項 $a _ N$ の値.
時間計算量 $\mathrm{O}(d \log d \log N)$
アルゴリズムの詳細については Links にあるページがわかりやすい.
ここでは LinearRecurrence(a, c, N) から BostanMori(Q, P, N) への帰着について説明する.
$d + 1$ 項間漸化式
\[a _ i = \sum _ {j = 1} ^ d c _ j a _ {i - j}\]について,その数列の母関数を
\[G(x) = \sum _ {i = 0} ^ \infty a _ i x ^ i\]とし,また
\[Q(x) = 1 - \sum _ {i = 1}^d c _ i x ^ i\]と定めるとき,$G(x) Q(x)$ は漸化式の定義より高々 $d - 1$ 次の多項式 $P(x)$ に一致する. 以上より,
\[a _ N = \lbrack x ^ N \rbrack \frac{P(x)}{Q(x)}\]となり,これは $\mathrm{O}(d \log d \log N)$ で計算することが可能である.
#pragma once
#include "../atcoder/convolution"
template <typename T> T BostanMori(std::vector<T> Q, std::vector<T> P, long long N) {
assert(Q[0] == 1);
assert(P.size() < Q.size());
const int d = Q.size();
for (; N; N >>= 1) {
auto Q_neg = Q;
for (int i = 1; i < int(Q.size()); i += 2) Q_neg[i] *= -1;
P = atcoder::convolution(P, Q_neg);
Q = atcoder::convolution(Q, Q_neg);
for (int i = N & 1; i < int(P.size()); i += 2) P[i >> 1] = P[i];
for (int i = 0; i < int(Q.size()); i += 2) Q[i >> 1] = Q[i];
P.resize(d - 1);
Q.resize(d);
}
return P[0];
}
/**
* @brief compute Nth term of linearly recurrent sequence a_n = \sum_{i = 1}^d c_i a_{n - i}
*
* @tparam T F_p
* @param a first d elements of the sequence a_0, a_1, ... , a_{d - 1}
* @param c coefficients of the linear recurrence c_1, c_2, ... , c_d
* @param N the number of term you want to calculate
* @return T Nth term of linearly recurrent sequence
*/
template <typename T> T LinearRecurrence(std::vector<T> a, std::vector<T> c, long long N) {
assert(a.size() >= c.size());
const int d = c.size();
std::vector<T> Q(d + 1);
Q[0] = 1;
for (int i = 0; i < d; i++) Q[i + 1] = -c[i];
std::vector<T> P = atcoder::convolution(a, Q);
P.resize(d);
return BostanMori(Q, P, N);
}Traceback (most recent call last):
File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/documentation/build.py", line 71, in _render_source_code_stat
bundled_code = language.bundle(stat.path, basedir=basedir, options={'include_paths': [basedir]}).decode()
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/languages/cplusplus.py", line 187, in bundle
bundler.update(path)
~~~~~~~~~~~~~~^^^^^^
File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/languages/cplusplus_bundle.py", line 401, in update
self.update(self._resolve(pathlib.Path(included), included_from=path))
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/languages/cplusplus_bundle.py", line 401, in update
self.update(self._resolve(pathlib.Path(included), included_from=path))
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/hostedtoolcache/Python/3.13.3/x64/lib/python3.13/site-packages/onlinejudge_verify/languages/cplusplus_bundle.py", line 260, in _resolve
raise BundleErrorAt(path, -1, "no such header")
onlinejudge_verify.languages.cplusplus_bundle.BundleErrorAt: atcoder/convolution.hpp: line -1: no such header