兩類遞推數列

此博客是抄論文的,你可以認爲是轉載的

1.線性遞推數列

有限數列顯然是線性遞推數列。
無限數列aia_i設其生成函數爲A(x)A(x)
那麼如果A(x)A(x)能被表示爲C(x)B(x)\frac {C(x)}{B(x)}的形式,其中B(x)[x0]=1B(x)[x^0] = 1,則A(x)A(x)是線性遞推數列。
常數項爲11是因爲遞推式你要讓j=0bjaij=0\sum_{j=0}b_ja_{i-j} = 0來遞推出aia_i所以常數項需要爲11
能這樣表示是因爲線性遞推實質上就是A(x)B(x)=C(x)A(x)B(x) = C(x),其中B(x)B(x)是我們的線性遞推式。

對於一個線性遞推數列aia_i,假設他前ii項的最短遞推式是R(i)R^{(i)},長度爲lil_i,那麼如果R(i1)R^{(i-1)}不是前ii項的最短遞推式,那麼有limax(li1,i+1li1)l_i \geq \max(l_{i-1},i+1-l_{i-1}),且這個等號是可以通過構造取到的。
首先lili1l_i \geq l_{i-1}顯然,如果liili1l_i \leq i-l_{i-1}的話:
在這裏插入圖片描述
實在不知道怎麼用語言表示交換和號。
也就是說如果liili1l_i \leq i-l_{i-1}那麼原來的遞推式必可以繼續用。

接下來我們給出在R(i1)R^{(i-1)}不是前ii項的遞推式時li=max(li1,i+1li1)l_i = \max(l_{i-1},i+1-l_{i-1})的構造方案,也就是BMBM算法。
在這裏插入圖片描述
也就是說每次增長遞推式,我們都可以用這個方法使得增長時li=i+1li1l_i = i+1-l_{i-1},不增長時li=li1l_i = l_{i-1}
因爲上文證明了limax(li1,i+1li1)l_i \geq \max(l_{i-1},i+1-l_{i-1}),所以這個算法對於有限長度的數列求出的遞推式一定是最短的。

對於無限長的數列,
在這裏插入圖片描述
所以我們只需要取最短遞推式長度的兩倍即可。
邊界情況:第一次增長遞推式的時候,aia_i應該是第一個非00元素,那麼li=il_i = i00即爲前ii個數的最短遞推式,也就是根本沒有遞推,同時也滿足lii+1li1,(li1=0)l_i \geq i+1-l_{i-1},(l_{i-1}=0)

線性遞推求第nn項:
在這裏插入圖片描述
代碼:luogu【模板】Berlekamp-Massey算法
在這裏插入圖片描述
Code:\mathcal Code:(真的很短。)

#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define maxn 10005
#define pb push_back
#define vi vector<int>
#define mod 998244353
using namespace std;

int n,m,a[maxn];
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod;return r; }
vi BM(int *a,int n){ // a[0 ~ n] is used
	vi r(1,1),p(1,0),t;int lt;
	rep(i,0,n){
		int d=0;
		rep(j,0,r.size()-1) d = (d + r[j] * 1ll * a[i-j]) % mod;		
		if(!d) continue;
		t = r;
		r.resize(max(p.size() , i+1-(p.size()-1)));
		rep(j,0,p.size()-1) r[j+i-lt] = (r[j+i-lt] - 1ll * d * p[j]) % mod;
		int iv = Pow(d , mod-2);
		p = t , lt = i;
		rep(i,0,p.size()-1) p[i] = 1ll * p[i] * iv % mod;
	}
	return r; // a \times r = const 
}
typedef vi poly;
poly Mul(const poly &A,const poly &B,const poly &P){
	poly r(A.size() + B.size() - 1);
	rep(i,0,A.size()-1) rep(j,0,B.size()-1) r[i+j] = (r[i+j] + 1ll * A[i] * B[j]) % mod;
	per(i,r.size()-1,P.size()-1) if(r[i]){// in this problem P[P.size()-1] = 1 , so there is no need to getinv.
		int t = r[i];
		rep(j,1,P.size())
			r[i-j+1] = (r[i-j+1] - 1ll * P[P.size()-j] * t) % mod;
	}
	r.resize(P.size()-1);
	return r;
}

int main(){
	scanf("%d%d",&n,&m);
	rep(i,0,n-1) scanf("%d",&a[i]);
	vi P = BM(a,n-1);
	rep(i,1,P.size()-1) printf("%d%c",(mod-(P[i]+mod)%mod) % mod," \n"[i==P.size()-1]);
	reverse(P.begin(),P.end());
	poly r(1,1),t(2,0);
	t[1] = 1;
	for(;m;m>>=1,t=Mul(t,t,P)) if(m&1)
		r = Mul(r,t,P);
	int ans = 0;
	rep(i,0,r.size()-1) ans = (ans + 1ll * r[i] * a[i]) % mod;
	printf("%d\n",(ans+mod)%mod);
}

向量序列的最短遞推式:
在這裏插入圖片描述

矩陣的零化多項式:使得矩陣MM
f(M)=i=0naiMi=0f(M) = \sum_{i=0}^n a_iM^i = 0
矩陣的最小多項式:
零化多項式中次數最低的多項式。
如何求矩陣的最小多項式:
直接求I,M,M2...{I,M,M^2...}的最短遞推式即可,對於稀疏矩陣可以做到O(n(n+e))O(n(n+e))
在這裏插入圖片描述
BM與矩陣的特徵多項式:
特徵多項式是矩陣的一個零化多項式,
BMBM求出的最小多項式也是矩陣的一個零化多項式
在這裏插入圖片描述
最小多項式是特徵多項式的一個因式,因爲如果不是則可以做帶餘除法得到餘式爲更小的零化多項式。
對於一個線性遞推問題,我們可以通過零化多項式得到線性遞推式,所以在解決線性遞推時可以找最小多項式(用BM),也可以求特徵多項式。
但是特徵多項式的最經典的解法是根據定義λIE=0|\lambda - IE| = 0來求行列式後拉格朗日插值求出多項式,O(n4)O(n^4)相較於BMO(n3)BMO(n^3)感覺沒有什麼競爭力,儘管特徵多項式有O(n3)O(n^3)的巧妙解法,但是這個解法無法計算出線性遞推的前nn項(就是不能用遞推式的部分),有了前nn項那爲什麼不用BMBM呢?
綜上在信息學奧賽的當前時代最小多項式完爆特徵多項式,很多打着特徵多項式的旗子的題目都可以用BM解決。

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2.整式遞推數列

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章