矩阵乘法算法 结合hdu1757讲解

一个矩阵就是一个二维数组,为了方便声明多个矩阵,我们一般会将矩阵封装一个类或定义一个矩阵的结构体,我采用的是后者:

struct Mat
{
    int mat[Max][Max];
}


最特殊的矩阵应该就是单位矩阵E了,它的对角线的元素为1,非对角线元素为0。

 

一般矩阵乘法采用朴素的O(n^3)的算法:

 Mat operator*(Mat a,Mat b)  
 {  
     int i,j,k;  
     Mat c;  
     for (i=0;i<len;i++)  
     {  
         for (j=0;j<len;j++)  
         {  
             c.mat[i][j] = 0;  
             for(k=0;k<len;k++)  
                 c.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%MOD;  
         }  
     }  
     return c;  
 }

在ACM的题目中,我们一般考虑的是n阶方阵之间的乘法以及n阶方阵与n维向量(把向量看成n×1的矩阵)的乘法。矩阵乘法最重要的性质就是满足结合律,同时它另一个很重要的性质就是满足交换率,这保证了矩阵的幂运算满足快速幂取模(A^x % MOD)算法:

假设k = 27,则k的二进制表示为11011,所以

,可以看出:k的二进制的每一位矩阵A都要平方,在k二进制为1的位:末矩阵×平方后的A,在k二进制为0的位则末矩阵×E(单位矩阵),即不变。代码如下:

Mat operator^(Mat a,int x)  
 {  
     Mat p = e,q = a;  
     while (x)  
     {  
         if(x&1)  
             p = p*q;  
         x>>=1;  
         q = q*q;  
     }  
     return p;  
 }

许多题目还要求S = A + A2 + A3 + … +Ak.。其实再作一次二分即可:只需计算log(n)个A的幂即可。

Mat solve(Mat a,int p)  
 {  
     if(p==1)  
         return a;
     /*如果p为奇数,则对p-1进行二分,a^p+二分结果*/
     /*
           A^1+A^2+A^3+A^4+A^5+A^6+A^7 = (A^1+A^2+A^3)+ A^3*(A^1+A^2+A^3)+A^7=A^7+solve(A,p-1)
     */
     else if(p&1)  
         return (a^p)+solve(a,p-1);  
     /*p为偶数,则直接二分*/
     /*
     A^1+A^2+A^3+A^4+A^5+A^6 = (A^1+A^2+A^3)+ A^3*(A^1+A^2+A^3) = (A^3+e)*(A^1+A^2+A^3)
     推广即可得到当p为偶数时   A^1+A^2+A^3+……+A^p = (A^(p/2)+e) * solve(A,p/2);
     */
     else  
         return ((a^(p>>1))+e)*solve(a,p>>1);  
 } 


hdu 1757

A Simple Math Problem

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1400    Accepted Submission(s): 800


Problem Description
Lele now is thinking about a simple function f(x).

If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
And ai(0<=i<=9) can only be 0 or 1 .

Now, I will give a0 ~ a9 and two positive integers k and m ,and could you help Lele to caculate f(k)%m.
 

Input
The problem contains mutiple test cases.Please process to the end of file.
In each case, there will be two lines.
In the first line , there are two positive integers k and m. ( k<2*10^9 , m < 10^5 )
In the second line , there are ten integers represent a0 ~ a9.
 

Output
For each case, output f(k) % m in one line.
 

Sample Input
  
  
10 9999 1 1 1 1 1 1 1 1 1 1 20 500 1 0 1 0 1 0 1 0 1 0
 

Sample Output
  
  
45 104
 

Author
linle
 

Source
 

Recommend
lcy


构建矩阵
|f(10) |      |a0 a1 a2 ...a8 a9|   |f(9)|
| f(9) |       | 1  0  0 ... 0  0|          |f(8)|
| .....|  =     |.. ... ... ... ..|                 | .. |
| f(2) |       | 0  0  0 ... 0  0|          |f(1)|
| f(1) |       | 0  0  0 ... 1  0|          |f(0)|


#include<stdio.h>
#include<string.h>
struct haha
{
	int mar[10][10];
}a,b,c;
int n,m;
struct haha multi(struct haha a1,struct haha a2)
{
	struct haha temp;
	int i,j,k;
	for(i=0;i<10;i++)
		for(j=0;j<10;j++)
		{
			temp.mar[i][j]=0;
			for(k=0;k<10;k++)
			{
				temp.mar[i][j]+=(a1.mar[i][k]*a2.mar[k][j])%m;
			}
			temp.mar[i][j]%=m;
		}
		return temp;

}
struct haha bin(int cnt)//二分思想  下面有更精简的方法
{
	struct haha tmp;
	if(cnt==1) return a;
	if(cnt%2==0) 
	{
		tmp=bin(cnt/2); return multi(tmp,tmp);
	}
	else  
	{
		tmp=bin((cnt-1)/2); tmp=multi(tmp,tmp);return multi(tmp,a);
	}
}
/*void matrix_binary()//二分思想也可以用二进制方法解决 
{
    while(k)
    {
        if(k & 1) //与1计算后可以得到二进制最后一位是否为1,为1就乘,不是就不乘          
            b = matrixmul(b,a);//注意 b的初始为E单位矩阵  
        a = matrixmul(a,a);
        k = k >> 1;
    }  
}
//上面原理解释: 假设k的二进制是10111 即为23 矩阵要乘23次  a始终用来记录2 4 8 16.......
当k=10111  b变成了a   a为2次矩阵相乘 当k=1011  b=b*a 为3次矩阵相乘  a变成了4次相乘
k=101 b为7次 a为8次 k=10 b为7次  a为16次  k=1  b为23 a=32 k=0 退出
那么这时候b就是我们得到的矩阵相乘结果23次
*/

int main()
{
          int i,j,ans;
		  while(scanf("%d %d",&n,&m)!=EOF)
		  {
		   //   for(i=0;i<10;i++)
			 //      for(j=0;j<10;j++)
			//	   {
			//	           if(i==j-1) a.mar[i][j-1]=1;//搞了整整一天没想到居然是在这里犯的错误啊  矩阵的初始化搞错了
			//			   else a.mar[i][j]=0;
			//	   }
		    memset(a.mar,0,sizeof(a.mar));
            for(i = 1;i < 10;i++)
                 a.mar[i][i-1] = 1;

			     for(j=0;j<10;j++)
				     scanf("%d",&a.mar[0][j]);
				 if(n<10) {printf("%d\n",n);continue;}
			  n=n-9;
			  c=bin(n);
			  ans=0;
		        for(i = 0;i < 10;i++)
                    ans += (c.mar[0][i] * (9-i)) % m;
                    printf("%d\n",ans%m);
		  }
		  return 0;
}



参考内容来自http://blog.csdn.net/q3498233/article/details/5786180

矩阵乘法大神解题报告http://www.cppblog.com/notonlysuccess/archive/2009/03/03/75405.aspx

矩阵乘法题目整理


矩阵乘法题目整理

http://acm.hdu.edu.cn/showproblem.php?pid=1575
http://acm.hdu.edu.cn/showproblem.php?pid=1757
赤裸裸的两道
http://acm.hdu.edu.cn/showproblem.php?pid=2256
这题正解不是矩阵,不过如果推出公式来的话可以用矩阵解
http://acm.hdu.edu.cn/showproblem.php?pid=2604
推公式吧,推完后矩阵求解(也是道正解不是矩阵的题)
http://acm.fzu.edu.cn/problem.php?pid=1683
我的第一道矩阵,不过求和的话比一般的难一点点
方法有两个.
1.增加一维,重新构造和的函数
2.详细见 http://acm.hdu.edu.cn/forum/read.php?tid=8137&keyword=%BE%D8%D5%F3
http://acm.hdu.edu.cn/showproblem.php?pid=1588
此题同上题一样
http://acm.hdu.edu.cn/showproblem.php?pid=3117
两个部分,前一个是黄金分割比,后一个是最裸的矩阵
http://acm.hdu.edu.cn/showproblem.php?pid=2254
经典题目,见下边资料
http://acm.hdu.edu.cn/showproblem.php?pid=2276
比较有趣并且隐藏的比较深的题
http://acm.fzu.edu.cn/problem.php?pid=1692
同上题一个原理,不过时限很紧,要降维优化
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2853
07年省赛题
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2974
08年省赛题
http://acm.hdu.edu.cn/showproblem.php?pid=2855
联合训练题
http://acm.hdu.edu.cn/showproblem.php?pid=2971
有点难推的公式
http://acm.hdu.edu.cn/showproblem.php?pid=2294
难题



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值