Advertisement

矩阵优化递推的总结(不定期更新,最后更新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

BK可以通过矩阵快速幂O(N3logK)算出

复制代码
 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)..都无所谓啦,。

然后计算斐波那契数列第k项时,在公式A*B^K=C中得到相应的数值;通过适当调整初始矩阵的元素值±1等方式来优化计算结果。

这个例子能发现些什么呢,呃。。没什么。。

[Noi2012]随机数生成器

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

简要描述:

给定数列递推式

求数列{X}的第n项 mod g。

数据范围:

nX_₀均不超过N时,在mac均为整数值的情况下(其中m为质数值),满足以下关系:

\begin{cases} n \leq N \\ X_₀ \leq N \end{cases}

其中m为一正整数值,

\begin{cases} |m| > 2 \\ |m| = 2 \\ |m| < 2 \end{cases}

这是一个一阶递推,可以尝试多种方法去解决下:

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

(2).求通项:

一般来说,在一阶的情况下仍然可以求得通项公式。然而到了二阶情况后使用特征根法可能会导致出现大量无理数系数(如同斐波那契数列)。

a==1 等差数列....不说了。

a!=1用什么不动点法之类的乱搞一下:

(a-1)^(phi(m)-1)

即(a-1)^(φ(m)-1)

这样加上暴力就有80分。

不错。但是不互质怎么办....

(3)矩阵乘法:

递推式里面有常数有系数 就可以这样搞转移矩阵。

边乘边模就行了,完全不用考虑m是不是质数。

By the way, this problem has a clever trick. When m is less than or equal to 10^18, directly multiplying will cause an overflow in a long long variable. Let me explain the fast multiplication method (also known as rapid multiplication), which transforms multiplication into addition for better efficiency. I won't go into detail here.

这大概不是NOI有史以来最水的题。。

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

[Noi2013]矩阵游戏

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

(虽然我还没写过) <- <>

F[1][1]=1
F[i,j]=aF[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, 123456789(此处数字应根据实际情况调整)。

看上去一切都很和谐,但是,真的用矩阵做好做吗??(什么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数列说事吧。

把上面那个矩阵加一维,稍稍改进一下就行了。

这是一个普适性极强的求和法。按理说任何数列都能求和吧。

目前遇到的问题通常可分为两类:一种涉及数位动态规划(number digit DP),另一种则通过矩阵快速幂(matrix exponentiation)来解决。面对N <10^18这样的情况,通常涉及数位动态规划或矩阵快速幂优化!解决这类问题的关键在于如何有效地应用矩阵优化方法。

2014年2月28日更新:

贴吧大神说矩阵也满足费马小定理?(亟待验证)

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

若该矩阵符合费马小定理,则这一矩阵游戏将会以另一种形式见了(以后有机会再深入探讨)

2014年3月21日更新:

若有多次询问,同一个矩阵矩阵乘的次数特别多,每次暴力乘是O(n^3logk)的。

乘m次就是O(M*N^3logK)

把转移矩阵的2的幂次方预处理出来存一下,每次不要再暴力算。

然后通过使用初始向量与经过预处理得到的幂次方矩阵相乘,从而实现单次查询时间复杂度为O(N² log k)

这样询问M次的复杂度就是O(N^3logK + M*N^2logK)

当M,N很大的时候,效果还是很明显的,比如矩阵来容斥。

全部评论 (0)

还没有任何评论哟~