矩阵乘法学习笔记

矩阵乘法是一种可以把递推优化到log(n)的一种算法。

矩阵乘法在运算的时候需要满足所相乘的两个矩阵的A的列数和矩阵B的行数相等时两个矩阵才可能想乘。比如一个矩阵A(2*3)和一个矩阵B(3*1)相乘可以得到一个矩阵C(2*1)的矩阵。

矩阵乘法在计算的时候满足结合律,但是不满足交换律,当我们在用矩阵乘进行计算的时候往往需要用到快速幂。

那么矩阵乘法的两项是如何运算的呢?

其实所得的矩阵的每一个位置i,j上的数就是矩阵A的第i行上的n个数和矩阵B的第j列上的n个数对应相乘再相加的和。

例如矩阵相乘:


在了解了矩阵乘法的计算规则以后就可以去做题了,放一道矩阵乘法的基础题:

CODEVS1250 Fibonacci数列

题目描述 Description

定义:f0=f1=1, fn=fn-1+fn-2(n>=2)。{fi}称为Fibonacci数列。

输入n,求fn mod q。其中1<=q<=30000。

输入描述 Input Description

第一行一个数T(1<=T<=10000)。

以下T行,每行两个数,n,q(n<=109, 1<=q<=30000)

输出描述 Output Description

文件包含T行,每行对应一个答案。

样例输入 Sample Input

3

6 2

7 3

7 11

样例输出 Sample Output

1

0

10

数据范围及提示 Data Size & Hint

1<=T<=10000

n<=109, 1<=q<=30000

虽然是个斐波那契数列,但是由于数据范围的限制,我们不可以用递推来求出第n项的结果,所以我们就想到了矩阵乘法我们要求的是发 f[n],但是f[n]是由f[n-1]+f[n-2]得来的,所以我们可以建立这样的两个矩阵


这样我们所得到的矩阵就变成了


至于为什么要这么做呢,是因为我们要求的f[n]是由f[n-1]+f[n-2]得出的,所以我们需要一个矩阵B,这样就可以得到矩阵C应该和矩阵B一样的是f[n]和f[n-1],所以我们就可以知道矩阵A为什么了。

我们还可以将上面的式子再一次进行转化,就可以得出最后的答案就是


的首项了。至于前面的x^(n-2)的运算,我们就可以用快速幂了。最后的答案即为所得出的第一项。

至于第0和1项就特判一下就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define F(i,x,y) for(i=x;i<=y;++i)
using namespace std;
int a[2][2],ans[2][2],n,m,t,c[2][2],b[2];
int main()
{
	scanf("%d",&t);
	while(t--){
		int i,j,out,y;
		a[0][0]=ans[0][0]=1;a[0][1]=ans[0][1]=1;
		a[1][0]=ans[1][0]=1;a[1][1]=ans[1][1]=0;
		b[0]=b[1]=1;
		scanf("%d%d",&n,&m);
		if(n<=1) printf("1\n");
		else{
			y=n-2;
			while(y){
				if(y&1){
					c[0][0]=(a[0][0]*ans[0][0]+a[0][1]*ans[1][0])%m;
					c[0][1]=(a[0][0]*ans[0][1]+a[0][1]*ans[1][1])%m;
					c[1][0]=(a[1][0]*ans[0][0]+a[1][1]*ans[1][0])%m;
					c[1][1]=(a[1][0]*ans[0][1]+a[1][1]*ans[1][1])%m;
					F(i,0,1)
					  F(j,0,1)
					    ans[i][j]=c[i][j];
				}
				y>>=1;
				c[0][0]=(a[0][0]*a[0][0]+a[0][1]*a[1][0])%m;
				c[0][1]=(a[0][0]*a[0][1]+a[0][1]*a[1][1])%m;
				c[1][0]=(a[1][0]*a[0][0]+a[1][1]*a[1][0])%m;
				c[1][1]=(a[1][0]*a[0][1]+a[1][1]*a[1][1])%m;
				F(i,0,1)
				  F(j,0,1)
					a[i][j]=c[i][j];
			}
			out=(ans[0][0]*b[0]+ans[0][1]*b[1])%m;
			printf("%d\n",out);
		}
	}
}


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值