寫在前面:
定義矩陣:
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日更新:
如果矩陣也滿足費馬小定理,那這個矩陣遊戲就直接再見了!!!!(有時間寫一寫)