上了高二学了数列,知道了如何给出递推求通项,也从数竞同学那里听来了高阶常系数齐次线性递推的通项求法。
那么OI上如何应用呢?
百度了一下发现自己在这一块的技能点为0,就决定学一学QwQ
线性代数渣没办法
若有常数 λ \lambda λ,向量 v → \overrightarrow v v,对于n阶矩阵A满足 λ v → = A v → \lambda\overrightarrow v=A\overrightarrow v λv=Av
那么称 λ \lambda λ为A的特征值, v → \overrightarrow v v为A的特征向量
有一个定理,秩为k的矩阵有k组线性无关的特征向量
我们把式子变一下形
( A − λ I ) v → = 0 (A-\lambda I)\overrightarrow v=0 (A−λI)v=0
I是单位矩阵
这个式子有解的充要条件为 d e t ( A − λ I ) = 0 det(A-\lambda I)=0 det(A−λI)=0
左边的东西显然是一个关于 λ \lambda λ的n次多项式,称作A的特征多项式
这个多项式的n个根就是n组特征值了
设矩阵A的特征多项式为f(x),那么f(A)=0
这里f(A)可以理解成把多项式里面的乘法换成矩阵乘法
证明:考虑写成 f ( A ) = ∏ i = 1 n ( λ i I − A ) f(A)=\prod_{i=1}^{n}(\lambda_i I-A) f(A)=∏i=1n(λiI−A)
如果对于每个特征向量 v i → \overrightarrow {v_i} vi都有 v i → f ( A ) = 0 \overrightarrow {v_i}f(A)=0 vif(A)=0,由于这些特征向量线性无关,所以有f(A)=0
考虑一个特征向量和其对应的特征值
v i → ( λ i I − A ) = v i → λ i I − v i → A \overrightarrow {v_i}(\lambda_i I-A)=\overrightarrow {v_i}\lambda_i I-\overrightarrow {v_i}A vi(λiI−A)=viλiI−viA
根据定义这个东西为0
Q.E.D
矩阵乘法不满足交换律?其实在这里满足,把式子拆一下就好了
特征多项式可以直接差值求,但在我们的这个问题里可以不用
( a 1 a 2 a 3 . . . a n 1 0 0 . . . 0 0 1 0 . . . 0 0 0 1 . . . 0 . . . . . . . . . . . . . . . 0 0 0 . . . 1 ) ( h n − 1 h n − 2 h n − 3 h n − 4 . . . h 0 ) = ( h n h n − 1 h n − 2 h n − 3 . . . h 1 ) \begin{pmatrix} a_1&a_2&a_3&...&a_n\\ 1&0&0&...&0\\ 0&1&0&...&0\\ 0&0&1&...&0\\ ...&...&...&...&...\\ 0&0&0&...&1 \end{pmatrix} \begin{pmatrix} h_{n-1}\\ h_{n-2}\\ h_{n-3}\\ h_{n-4}\\ ...\\ h_0 \end{pmatrix}= \begin{pmatrix} h_n\\ h_{n-1}\\ h_{n-2}\\ h_{n-3}\\ ... \\ h_1 \end{pmatrix} ⎝⎜⎜⎜⎜⎜⎜⎛a1100...0a2010...0a3001...0..................an000...1⎠⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎛hn−1hn−2hn−3hn−4...h0⎠⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎛hnhn−1hn−2hn−3...h1⎠⎟⎟⎟⎟⎟⎟⎞
f ( λ ) = ∣ ( λ − a 1 − a 2 − a 3 . . . − a n − 1 − a n − 1 λ 0 . . . 0 0 0 − 1 λ . . . 0 0 . . . . . . . . . . . . . . . . . . 0 0 0 . . . − 1 λ ) ∣ f(\lambda)=| \begin{pmatrix} \lambda-a1&-a2&-a3&...&-a_{n-1}&-an\\ -1&\lambda&0&...&0&0\\ 0&-1&\lambda&...&0&0\\ ...&...&...&...&...&...\\ 0&0&0&...&-1&\lambda \end{pmatrix} | f(λ)=∣⎝⎜⎜⎜⎜⎛λ−a1−10...0−a2λ−1...0−a30λ...0...............−an−100...−1−an00...λ⎠⎟⎟⎟⎟⎞∣
根据第一行展开 f ( λ ) = ( λ − a 1 ) A 1 , 1 + ( − a 2 ) A 1 , 2 + ( − a 3 ) A 1.3 . . . + ( − A n ) A 1 , n f(\lambda)=(\lambda-a_1)A_{1,1}+(-a2)A_{1,2}+(-a3)A_{1.3}...+(-An)A_{1,n} f(λ)=(λ−a1)A1,1+(−a2)A1,2+(−a3)A1.3...+(−An)A1,n
其中 A i , j A_{i,j} Ai,j表示A的代数余子式
显然所有余子式都是下三角矩阵,行列式很容易求得
那么我们得到了 f ( λ ) = λ n − ∑ i = 1 n a i λ n − i f(\lambda)=\lambda^n-\sum_{i=1}^{n}ai\lambda^{n-i} f(λ)=λn−i=1∑naiλn−i
所谓特征多项式(刚好是特征根的形式的说)
回到原问题,我们要求形如 H ∗ A m H*A^m H∗Am的式子
我们知道 f ( A ) = 0 f(A)=0 f(A)=0,所以 A m = A m m o d    f ( A ) A^m=A^m \mod f(A) Am=Ammodf(A)
做多项式取模我们得到了一个关于A的n-1次多项式,记为 ∑ i = 0 n − 1 c i A i \sum_{i=0}^{n-1}c_iA^i ∑i=0n−1ciAi
那么我们要求的就是 ∑ i = 0 n − 1 c i A i H \sum_{i=0}^{n-1}c_iA^iH ∑i=0n−1ciAiH的第m项
而 A i H = h i + n A^iH=h_{i+n} AiH=hi+n,也就是 ∑ i = 0 k − 1 c i h i + k \sum_{i=0}^{k-1}c_ih_{i+k} ∑i=0k−1cihi+k
那么我们先O(n^2)把 h n . . . h 2 ∗ n − 1 h_n...h_{2*n-1} hn...h2∗n−1计算出来就好了
多项式取模可以用NTT也可以直接暴力
直接O(k^2 log k)求出 x n % f ( x ) x^n\%f(x) xn%f(x)
注意特判k=1的情况(虽然数据没有)
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=4e3+5,Mo=1e9+7;
int n,k,a[N],h[N],f[N],g[N],b[N],an[N];
void mul(int *a,int *b,int *c) {
fo(i,0,2*k-2) g[i]=0;
fo(i,0,k-1) fo(j,0,k-1) (g[i+j]+=(ll)a[i]*b[j]%Mo)%=Mo;
fd(i,2*k-2,k)
fd(j,k-1,0)
(g[i-k+j]-=(ll)g[i]*f[j]%Mo)%=Mo;
fo(i,0,k-1) c[i]=g[i];
}
int main() {
scanf("%d%d",&n,&k);
fo(i,1,k) scanf("%d",&a[i]);
fo(i,0,k-1) scanf("%d",&h[i]);
if (n1) b[1]=1;
else b[0]=-f[0];
an[0]=1;
for(n-=k-1;n;n>>=1) {
if (n&1) mul(an,b,an);
mul(b,b,b);
}
fo(i,k,2*k-1)
fo(j,1,k)
(h[i]+=(ll)h[i-j]*a[j]%Mo)%=Mo;
int ans=0;
fo(i,0,k-1) (ans+=(ll)an[i]*h[i+k-1]%Mo)%=Mo;
printf("%d\n",(ans+Mo)%Mo);
return 0;
}