Luogu P4732 常係數齊次線性遞推
阿新 • • 發佈:2021-07-21
\(\mathtt{Description}\)
求一個滿足 \(k\) 階齊次線性遞推數列 \({a_i}\) 的第 \(n\) 項,即:
\[a_n=\sum\limits_{i=1}^{k}f_i \times a_{n-i} \]\(\mathtt{restrictions:}n=10^9,k = 32000\)
\(\mathtt{Solution}\)
\(\mathtt{Pre-Knowledge}\)
多項式取模。
關於求線性遞推數列的解法BJpers2大佬的題解已經說的很清楚了,這裡主要寫一下在打程式碼的時候需要注意的地方。
我們其實就是要求多項式 \(x^n\) 在 \(p(x)= x^k-f_1x^{k-1}-\cdots -f_kx^0\)
所以可以考慮快速冪,每次多項式取模就可以了,然後要注意以下兩個點:
-
對於多項式封裝使用
std::vector
的同學,需要注意模的多項式的size
大於原多項式的情況。 -
原式有小於 \(0\) 的情況,需要判斷掉。
把程式碼放一下吧:
\(\mathtt{Code}\)
inline std::pair<vector<int>,vector<int> > Div(vector <int> f,vector <int> g) { int n = f.size(),m = g.size(); if (n - m < 0) return std::make_pair(vector <int> (1,0),f) ; vector <int> fr(n),gr(m),igr,q(n - m + 1),r(m); for (int i = 0; i < n; ++i) fr[n - i - 1] = f[i] ; for (int i = 0; i < m; ++i) gr[m - i - 1] = g[i] ; gr.resize(n - m + 1) ; igr = Inv(gr),fr = fr * igr ; for (int i = 0; i < n - m + 1; ++i) q[i] = fr[n - m - i] ; g = q * g ; for (int i = 0; i < m; ++i) r[i] = (f[i] - g[i] + mod) % mod ; return std::make_pair(q,r) ; } inline int LR(vector<int> a,vector<int> p,int n) { int k = a.size() ; vector<int> f(2),res(1) ; f[1] = res[0] = 1; while (n) { if (n & 1) { res = res * f; auto tmp = Div(res,p) ; res = tmp.second ; } f = f * f ; auto temp = Div(f,p) ; f = temp.second,n >>= 1; } int ans = 0 ; for (int i = 0; i < k; ++i) ans = (ans + 1ll * a[i] * res[i] % mod) % mod ; return ans ; }