矩阵优化递推的总结(不定期更新,最后更新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很大的时候,效果还是很明显的,比如矩阵来容斥。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章