日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

常系数齐次线性递推学习笔记

發(fā)布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 常系数齐次线性递推学习笔记 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

定義

對于數(shù)列fff,如果有遞推式

fn=∑i=1kai×fn?i(n≥k)f_n=\sum_{i=1}^k a_i\times f_{n-i} \quad (n\geq k)fn?=i=1k?ai?×fn?i?(nk)

并且已知前kkk項,可稱其為kkk 階齊次線性遞推數(shù)列。

這個算法可以快速求出fff的第nnn項,復(fù)雜度為O(k2log?n)O(k^2\log n)O(k2logn),可優(yōu)化至O(klog?klog?n)O(k\log k\log n)O(klogklogn)

前置知識

矩陣快速冪

不難看出矩陣快速冪可以解決這個問題

我們構(gòu)造kkk轉(zhuǎn)移矩陣

A=(a1a2a3?ak?1ak100?00010?00001?00??????000?10)A=\left( \begin{matrix} a_1&a_2&a_3&\cdots&a_{k-1}&a_k\\ 1&0&0&\cdots&0&0\\ 0&1&0&\cdots&0&0\\ 0&0&1&\cdots&0&0\\ \vdots&\vdots&\vdots&\ddots&\vdots&\vdots\\ 0&0&0&\cdots&1&0 \end{matrix} \right)A=??????????a1?100?0?a2?010?0?a3?001?0????????ak?1?000?1?ak?000?0???????????

對于一個狀態(tài)

S=(fi+k?1fi+k?2??fi+1fi)S=\left( \begin{matrix} f_{i+k-1}\\ f_{i+k-2}\\ \vdots\\ \vdots\\ f_{i+1}\\ f_{i} \end{matrix} \right) S=???????????fi+k?1?fi+k?2???fi+1?fi?????????????

左乘上轉(zhuǎn)移矩陣即可得到下一個狀態(tài)

AS=(fi+kfi+k?1??fi+2fi+1)AS=\left( \begin{matrix} f_{i+k}\\ f_{i+k-1}\\ \vdots\\ \vdots\\ f_{i+2}\\ f_{i+1} \end{matrix} \right) AS=???????????fi+k?fi+k?1???fi+2?fi+1?????????????

我們只需要求出AnSA^nSAnS就可以算出答案

直接求的復(fù)雜度是O(k3log?n)O(k^3\log n)O(k3logn),不可接受

接下來將對矩陣快速冪進(jìn)行優(yōu)化

特征向量、值、多項式、方程

對于一個kkk階方陣AAA,如果有列向量xxx和實數(shù)λ\lambdaλ,滿足

Ax=λxAx=\lambda xAx=λx

我們稱xxxAAA特征向量λ\lambdaλAAA對于xxx特征值

對這個式子變形

(λI?A)x=0(\lambda I-A)x=0(λI?A)x=0

其中IIIkkk階單位矩陣

鬼知道我為什么要寫這個

我們記關(guān)于λ\lambdaλ的多項式

f(λ)=∣λI?A∣f(\lambda)=|\lambda I-A|f(λ)=λI?A

AAA特征多項式

f(λ)=0f(\lambda)=0f(λ)=0稱為特征方程,不過我們用不上

Caylay-Hamilton 定理

定理內(nèi)容:對于方陣AAA,設(shè)f(λ)f(\lambda)f(λ)為其特征多項式,有f(A)=0f(A)=0f(A)=0

你沒看錯,f(A)f(A)f(A)是矩陣的多項式,就是把矩陣AAA代進(jìn)去,計算a0I+a1A+a2A2+?+akAka_0I+a_1A+a_2A^2+\dots+a_kA^ka0?I+a1?A+a2?A2+?+ak?Ak得到一個零矩陣

證明有太多前置知識,我還不會,希望有生之年能補上。

代數(shù)余子式

余子式:一個矩陣AAA去掉Ai,jA_{i,j}Ai,j?所在的第iii行第jjj列后的行列式稱為余子式(對就是矩陣樹那樣),記為ai,ja_{i,j}ai,j?,是個具體的數(shù)

代數(shù)余子式:(?1)i+jai,j(-1)^{i+j}a_{i,j}(?1)i+jai,j?

引理 矩陣的行列式等于它第一行的代數(shù)余子式之和。

對于第111行第iii個元素,因為是第一行,所以貢獻(xiàn)的逆序?qū)€數(shù)為i?1i-1i?1,剛好和代數(shù)余子式的(?1)i+j(-1)^{i+j}(?1)i+j消掉,去掉第111行第iii列之后順序沒有任何影響,所以乘一個ai,ja_{i,j}ai,j?即可

算法流程

考慮之前的矩陣快速冪,最后推到了AnSA^nSAnS

我們考慮怎么快速求出AnA^nAn

我們發(fā)現(xiàn)AnA^nAn是一個矩陣的多項式,考慮前面的CH定理

我們設(shè)AAA的特征多項式為f(λ)f(\lambda)f(λ)

那么我們可以把AnA^nAn寫成

An=f(A)g(A)+h(A)A^n=f(A)g(A)+h(A)An=f(A)g(A)+h(A)

因為f(A)=0f(A)=0f(A)=0,所以

An=h(A)A^n=h(A)An=h(A)

也就是說,AnA^nAnh(A)h(A)h(A)在矩陣意義上等價

那么如果我們知道AAA的特征多項式,我們就可以用一般意義下的多項式取模(具體做法后面講)算出h(A)h(A)h(A)的表達(dá)式,并且最高項次數(shù)不超過k?1k-1k?1

我們設(shè)求出的

h(x)=∑i=0k?1bixih(x)=\sum_{i=0}^{k-1}b_ix^ih(x)=i=0k?1?bi?xi

考慮我們要求的

AnSA^nSAnS

因為An=h(A)A^n=h(A)An=h(A),所以等于

∑i=0k?1biAiS\sum_{i=0}^{k-1}b_iA^iSi=0k?1?bi?AiS

AiSA^iSAiS相當(dāng)于是第i+1i+1i+1個狀態(tài),我們寫成矩陣形式

∑i=0k?1bi(fi+k?1fi+k?2??fi+1fi)=AnS=(fn+k?1fn+k?2??fn+1fn)\sum_{i=0}^{k-1}b_i\left(\begin{matrix} f_{i+k-1}\\ f_{i+k-2}\\ \vdots\\ \vdots\\ f_{i+1}\\ f_{i} \end{matrix}\right)=A^nS=\left(\begin{matrix} f_{n+k-1}\\ f_{n+k-2}\\ \vdots\\ \vdots\\ f_{n+1}\\ f_n \end{matrix}\right) i=0k?1?bi????????????fi+k?1?fi+k?2???fi+1?fi?????????????=AnS=???????????fn+k?1?fn+k?2???fn+1?fn?????????????

仔細(xì)觀察,發(fā)現(xiàn)我們只需要最下面的元素

所以

∑i=0k?1bifi=fn\sum_{i=0}^{k-1}b_if_i=f_ni=0k?1?bi?fi?=fn?

也就是把bbb和題目給的前kkk項對應(yīng)乘起來就好了


現(xiàn)在的問題是如何求特征多項式

λI?A=(λ?a1?a2?a3?a4??ak?1?ak?1λ00?000?1λ0?0000?1λ?00???????0000?λ00000??1λ)\lambda I-A=\left(\begin{matrix} \lambda-a_1&-a_2&-a_3&-a_4&\cdots&-a_{k-1}&-a_k\\ -1&\lambda&0&0&\cdots&0&0\\ 0&-1&\lambda&0&\cdots&0&0\\ 0&0&-1&\lambda&\cdots&0&0\\ \vdots&\vdots&\vdots&\vdots&\ddots&\vdots&\vdots\\ 0&0&0&0&\cdots&\lambda&0\\ 0&0&0&0&\cdots&-1&\lambda \end{matrix}\right) λI?A=????????????λ?a1??100?00??a2?λ?10?00??a3?0λ?1?00??a4?00λ?00??????????ak?1?000?λ?1??ak?000?0λ?????????????

根據(jù)上面的引理,

∣λI?A∣=(λ?a1)a1,1+∑i=2k(?1)i+1(?ai)a1,i|\lambda I-A|=(\lambda-a_1)a_{1,1}+\sum_{i=2}^k(-1)^{i+1}(-a_i)a_{1,i}λI?A=(λ?a1?)a1,1?+i=2k?(?1)i+1(?ai?)a1,i?

其中ai,ja_{i,j}ai,j?為余子式

因為去掉第111行和任意一列后剩下的是一個下三角矩陣,并且對角線上刪除的列的左邊是?1-1?1,右邊是λ\lambdaλ,所以

a1,i=(?1)i?1λk?ia_{1,i}=(-1)^{i-1}\lambda^{k-i}a1,i?=(?1)i?1λk?i

所以

∣λI?A∣=(λ?a1)λk?1+∑i=2kaiλk?i=λk?∑i=1kaiλk?i|\lambda I-A|=(\lambda-a_1)\lambda^{k-1}+\sum_{i=2}^ka_i\lambda^{k-i}\\=\lambda^k-\sum_{i=1}^ka_i\lambda^{k-i}λI?A=(λ?a1?)λk?1+i=2k?ai?λk?i=λk?i=1k?ai?λk?i

f(λ)=λk?∑i=1kaiλk?if(\lambda)=\lambda^k-\sum_{i=1}^ka_i\lambda^{k-i}f(λ)=λk?i=1k?ai?λk?i

就是特征多項式

實現(xiàn)

前面的多項式取模部分是挖了坑的

An=f(A)g(A)+h(A)A^n=f(A)g(A)+h(A)An=f(A)g(A)+h(A)

我們已知f(A)f(A)f(A)為特征多項式,要求出余數(shù)h(A)h(A)h(A)

因為nnn很大,所以我們倍增計算并順便取模

常用的暴力取模好寫的多,復(fù)雜度O(k2log?n)O(k^2\log n)O(k2logn),具體實現(xiàn)見代碼注釋

BZOJ4161 Shlw loves matrixI

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #define MAXN 4005//數(shù)組開兩倍 using namespace std; int n,k,F[MAXN],R[MAXN],H[MAXN]; const int MOD=1e9+7; typedef long long ll; inline int add(const int& x,const int& y){return x+y>=MOD? x+y-MOD:x+y;} inline void mul(int* f,int* g,int* to) {static int t[MAXN];memset(t,0,sizeof(t));for (int i=0;i<k;i++)for (int j=0;j<k;j++)t[i+j]=add(t[i+j],(ll)f[i]*g[j]%MOD);//求卷積for (int i=(k<<1);i>=k;t[i--]=0)for (int j=1;j<=k;j++) t[i-j]=add(t[i-j],(ll)t[i]*F[j]%MOD);//因為最高項次數(shù)為1,后面都是讀入的數(shù)的相反數(shù),所以讀入不取負(fù),這里的減改成加即可for (int i=0;i<k;i++) to[i]=t[i]; } inline void qpow(int* f,int p) {static int ans[MAXN];memset(ans,0,sizeof(ans));ans[0]=1;while (p){if (p&1) mul(f,ans,ans);mul(f,f,f);p>>=1;}for (int i=0;i<k;i++) f[i]=ans[i]; } int main() {scanf("%d%d",&n,&k);for (int i=1;i<=k;i++) scanf("%d",&F[i]),F[i]<0&&(F[i]+=MOD);for (int i=0;i<k;i++) scanf("%d",&H[i]),H[i]<0&&(H[i]+=MOD);R[1]=1;qpow(R,n);int ans=0;for (int i=0;i<k;i++) ans=add(ans,(ll)R[i]*H[i]%MOD);printf("%d\n",ans);return 0; }

如果不幸遇到了毒瘤出題人,則需要用多項式全家桶中的多項式取模

復(fù)雜度為O(klog?klog?n)O(k\log k\log n)O(klogklogn),常數(shù)較大

Luogu P4723

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #define MAXN 131072 using namespace std; inline int read() {int ans=0,f=1;char c=getchar();while (!isdigit(c)) (c=='-')&&(f=-1),c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return f*ans; } const int MOD=998244353; typedef long long ll; inline int add(const int& x,const int& y){return x+y>=MOD? x+y-MOD:x+y;} inline int dec(const int& x,const int& y){return x<y? x-y+MOD:x-y;} inline int qpow(int a,int p) {int ans=1;while (p){if (p&1) ans=(ll)ans*a%MOD;a=(ll)a*a%MOD;p>>=1;}return ans; } #define inv(x) qpow(x,MOD-2) int rt[2][24]; int l,lim,r[MAXN]; inline void init(){lim=1<<l;for (int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));} inline void NTT(int* a,int type) {for (int i=0;i<lim;i++) if (i<r[i]) swap(a[i],a[r[i]]);for (int L=0;L<l;L++){int mid=1<<L,len=mid<<1,Wn=rt[type][L+1];for (int s=0;s<lim;s+=len)for (int k=0,w=1;k<mid;k++,w=(ll)w*Wn%MOD){int x=a[s+k],y=(ll)w*a[s+mid+k]%MOD;a[s+k]=add(x,y);a[s+mid+k]=dec(x,y);}}if (type){int t=inv(lim);for (int i=0;i<lim;i++) a[i]=(ll)a[i]*t%MOD;} } void getinv(int* A,int* B,int n) {static int f[MAXN],t[MAXN];if (n==1) return (void)(*B=inv(*A));getinv(A,t,(n+1)>>1);for (l=0;(1<<l)<(n<<1);l++);init();for (int i=0;i<n;i++) f[i]=A[i];for (int i=n;i<lim;i++) f[i]=t[i]=0;NTT(f,0);NTT(t,0);for (int i=0;i<lim;i++) B[i]=(ll)t[i]*dec(2,(ll)f[i]*t[i]%MOD)%MOD;NTT(B,1);for (int i=n;i<lim;i++) B[i]=0; } void getmod(int* A,int* B,int n,int m) {static int f[MAXN],g[MAXN],h[MAXN],t[MAXN];for (int i=0;i<=n;i++) f[i]=A[n-i];for (int i=0;i<=m;i++) g[i]=B[m-i];getinv(g,t,n-m+1);for (int i=n-m+1;i<lim;i++) f[i]=0;NTT(f,0);NTT(t,0);for (int i=0;i<lim;i++) h[i]=(ll)f[i]*t[i]%MOD;NTT(h,1);for (int i=n-m+1;i<lim;i++) h[i]=0;reverse(h,h+n-m+1),reverse(g,g+m+1);for (l=0;(1<<l)<=n;l++);init();for (int i=m+1;i<lim;i++) g[i]=0;for (int i=n-m+1;i<lim;i++) h[i]=0;NTT(g,0);NTT(h,0);for (int i=0;i<lim;i++) g[i]=(ll)g[i]*h[i]%MOD;NTT(g,1);for (int i=0;i<m;i++) A[i]=dec(A[i],g[i]);for (int i=m;i<lim;i++) A[i]=0; } int n,k; inline void mul(int* A,int* B,int* C,int* M) {static int f[MAXN],g[MAXN];for (int i=0;i<k;i++) f[i]=A[i],g[i]=B[i];for (l=0;(1<<l)<(k<<1);l++);init();for (int i=k;i<lim;i++) f[i]=g[i]=0;NTT(f,0);NTT(g,0);for (int i=0;i<lim;i++) C[i]=(ll)f[i]*g[i]%MOD;NTT(C,1);getmod(C,M,(k-1)<<1,k); } inline void qpow(int* A,int* R,int p) {static int ans[MAXN];memset(ans,0,sizeof(ans));ans[0]=1;while (p){if (p&1) mul(ans,A,ans,R);mul(A,A,A,R);p>>=1;}for (int i=0;i<k;i++) A[i]=ans[i]; } int f[MAXN],a[MAXN],h[MAXN]; int main() {rt[0][23]=qpow(3,119);rt[1][23]=inv(rt[0][23]);for (int i=23;i>=1;i--) rt[0][i-1]=(ll)rt[0][i]*rt[0][i]%MOD,rt[1][i-1]=(ll)rt[1][i]*rt[1][i]%MOD;n=read(),k=read();for (int i=1;i<=k;i++) (f[k-i]=-read())<0&&(f[k-i]+=MOD);for (int i=0;i<k;i++) (a[i]=read())<0&&(a[i]+=MOD);f[k]=1;h[1]=1;qpow(h,f,n);int ans=0;for (int i=0;i<k;i++) ans=add(ans,(ll)h[i]*a[i]%MOD);printf("%d\n",ans);return 0; }

總結(jié)

以上是生活随笔為你收集整理的常系数齐次线性递推学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。