矩陣優化遞推的總結(不定期更新,最後更新20140321)

寫在前面:

定義矩陣:

struct Matrix{
	LL a[MAX_K][MAX_K],n,m;//n行 m列
	Matrix(int _n = 0,int _m = 0):n(_n),m(_m){rep(i,1,n)rep(j,1,m) a[i][j]=0;}
	void dw(int _n,int _m){n=_n,m=_m;rep(i,1,n)rep(j,1,m) a[i][j]=(i==j?1:0);}
	LL& operator ()(int i,int j){return a[i][j];}
	void print(){rep(i,1,n) rep(j,1,m) printf("%I64d%c",a[i][j],j==m?'\n':' ');}
};

矩陣乘法:

優化遞推主要應用到矩陣乘法(當然如果要說特徵根方程求通項的話....),先簡單介紹一下矩陣乘法(可以無視掉):

定義矩陣A,B。

當且僅當A .m==B.n時 矩陣A,B可乘。

A(x,y)*B(y,z)=C(x,z)

其中每一個元素 Cij=Aik*Bkj (1<=k<=y)

矩陣乘法滿足結合律與分配律,結合律是矩陣能夠優化遞推的關鍵所在。


矩陣優化遞推的一般方法:

構建一個N維向量A(1,n),一個N*N的轉移矩陣B(n,n)

A(1,n)*B(n,n)=C(1,n)  我們發現C與A 同階,C 又能乘B ...就這樣一直遞推到需要的一項。

但一般先寫出A和下一項C ,再來倒推轉移矩陣B 


矩陣快速冪:

矩陣乘法一次是O(n^3)的,單憑矩陣乘法優化遞推是不可行的。

當然,上面說過矩陣乘法滿足結合律,我們考慮矩陣快速冪!

比如要得到遞推式的第K項,相當於計算 A*B^K=C

B^K可以通過矩陣快速冪O(N^3logK)算出

Matrix operator *(Matrix a,Matrix b){//矩陣乘法
	Matrix res(a.n,b.m);
	rep(i,1,a.n) rep(j,1,b.m) rep(k,1,a.m)
		(res(i,j)+=a(i,k)*b(k,j))%=MOD;
	return res;
}
Matrix operator ^(Matrix a,LL x){//快速冪
	Matrix res;res.dw(a.n,a.m);
	for (;x;a=a*a,x>>=1)
		if (x&1) res=res*a;
	return res;
}

矩陣的重要性質:

貼吧大神說矩陣也滿足費馬小定理?(亟待驗證)

http://tieba.baidu.com/p/2472273208


幾個矩陣優化的大類:

1.求數列第K項

求fibonacci數列(1,1,2,3,5...)第K項

這個應該是矩陣優化最基礎的了,大家都會。

令Fi表示fibonacci數列第i項


構造向量 A=(Fi,Fi-1),他的下一項是C=(Fi+1,Fi)

倒推轉移矩陣B   A*B=C


初始是(F1,F0).(F2,F1)..都無所謂啦,。

然後求fibonacci數列第k項就是 A*B^K=C 中的值,根據初始矩陣選值調整一下+-1什麼的...


這個例子能發現些什麼呢,呃。。沒什麼。。


[Noi2012]隨機數生成器

http://www.lydsy.com/JudgeOnline/problem.php?id=2875

簡要描述:

給定數列遞推式 求數列{X}的第n項 mod g。

數據範圍:

1: n<=100, m,a,c,X0<=100 m是質數
2: n<=1000, m,a,c,X0<=1000 m是質數
3: n<=10^4, m,a,c,X0<=10^4 m是質數
4: n<=10^4, m,a,c,X0<=10^4 m是質數
5: n<=10^5, m,a,c,X0<=10^4 m與a-1互質
6: n<=10^5, m,a,c,X0<=10^4 m與a-1互質
7: n<=10^5, m,a,c,X0<=10^4 m與a-1互質
8: n<=10^6, m,a,c,X0<=10^4
9: n<=10^6, m,a,c,X0<=10^9 m是質數
10:n<=10^6, m,a,c,X0<=10^9
11:n<=10^12, m,a,c,X0<=10^9 m是質數
12:n<=10^12, m,a,c,X0<=10^9 m是質數
13:n<=10^16, m,a,c,X0<=10^9 m與a-1互質
14:n<=10^16, m,a,c,X0<=10^9 m與a-1互質
15:n<=10^16, m,a,c,X0<=10^9
16:n<=10^18, m,a,c,X0<=10^9
17:n<=10^18, m,a,c,X0<=10^9
18:n<=10^18, m,a,c,X0<=10^18 m是質數
19:n<=10^18, m,a,c,X0<=10^18 m與a-1互質
20:n<=10^18, m,a,c,X0<=10^18


這是一個一階遞推,可以嘗試多種方法去解決下:

(1)暴力就不說了。。50分。

(2).求通項:

通項一般一階還能求,上了二階之後用特徵根似乎就會冒出很多無理數係數..(就像上面的fibonacci)

a==1 等差數列....不說了。

a!=1用什麼不動點法之類的亂搞一下:


發現裏面有個除法,看數據範圍,裏面有很多m是質數或者m與a-1互質,可以用Euler定理【(a-1)^(phi(m)-1)】或者擴展歐幾里德求出逆元化除爲乘,

這樣加上暴力就有80分。

不錯。但是不互質怎麼辦....

(3)矩陣乘法:


遞推式裏面有常數有係數 就可以這樣搞轉移矩陣。

邊乘邊模就行了,完全不用考慮m是不是質數。


By the way,這題還有個trick,m<=10^18次方,直接乘是要爆long long 的。 寫個龜速乘(這名字..),就是化乘爲加,這裏不介紹了。

這大概不是NOI有史以來最水的題。。




另外也不是所有遞推用矩陣都是最好的,例如:


 [Noi2013]矩陣遊戲 

(雖然我還沒寫過)    <-  http://blog.csdn.net/sdogsq/article/details/20129081

F[1][1]=1
F[i,j]=a*F[i][j-1]+b (j!=1)
F[i,1]=c*F[i-1][m]+d (i!=1)
遞推式中a,b,c,d都是給定的常數。

現在婷婷想知道F[n][m]的值是多少,請你幫助她。由於最終結果可能很大,你只需要輸出F[n][m]除以1,000,000,007的餘數。



看上去一切都很和諧,但是,真的用矩陣做好做嗎??(什麼log10快速冪....)

這題的重點是模的是一個質數!!!!

所以我們只用求出來F[n][m]的通項就可以了!

注意到n,m是巨大無比的,但是我們的MOD是質數啊~

費馬小定理 a^(p-1)=1 (%p)

所以我們的a^n = a^(n%(p-1)) (% p)

再用之求逆元....

搞了半天一個快速冪就行了。


這又說明了什麼呢,如果模的不是質數或者關鍵的東西不互質,,就是求不出逆元的話。矩陣是首先考慮的。

當然MOD 是一個質數當然也要考慮矩陣,不過也可以考慮看看能不能直接求通項,比如說矩陣想不出來。 看哪種好吧。

靈活使用什麼Euler定理,什麼數論的...我們這些數學蒟蒻..怎麼辦啊。。


2.求數列前K項和。

上面的都是求數列第K項是多少,還有的題是求數列前K項的和。Sum=F1+F2+...+Fk

其實這個也很簡單啦。

還是拿Fibonacci數列說事吧。

把上面那個矩陣加一維,稍稍改進一下就行了。


這是一個普適性極強的求和法。按理說任何數列都能求和吧。


我目前見到的一般就是上面兩類問題(以後見到其他類別還會添加),但矩陣不會考很裸的題,看到N<10^18之類的不是噁心的數位DP就是矩陣優化!
其實矩陣的題關鍵在於到底該怎麼用矩陣優化。 




2014年2月28日更新:

貼吧大神說矩陣也滿足費馬小定理?(亟待驗證)

http://tieba.baidu.com/p/2472273208


如果矩陣也滿足費馬小定理,那這個矩陣遊戲就直接再見了!!!!(有時間寫一寫)


2014年3月21日更新:

若有多次詢問,同一個矩陣矩陣乘的次數特別多,每次暴力乘是O(n^3logk)的。
乘m次就是O(M*N^3logK)
把轉移矩陣的2的冪次方預處理出來存一下,每次不要再暴力算。
然後直接用初始的向量去乘預處理出來的冪次方矩陣,就能做到單次詢問O(N^2logk)
這樣詢問M次的複雜度就是O(N^3logK + M*N^2logK) 
當M,N很大的時候,效果還是很明顯的,比如矩陣來容斥。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章