hdu5015(2014西安网赛) 233 Matrix

本文介绍了一种利用矩阵快速幂解决特定类型数学问题的方法。通过构造特定的矩阵和向量,可以高效地求解杨辉三角形变化形式的问题。文章详细解释了如何将问题转化为矩阵运算,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        题意:一个矩阵M,M[i][j]=M[i-1][j]+M[i][j-1],就像杨辉三角一样。矩阵的第一行是0,233,2333,23333......,第一列由输入给出。求矩阵第n行m列的值模10000007后的数。

        思路:矩阵快速幂。比赛的时候,隐约觉得这题是矩阵快速幂,但是不会写,因为以前没构造过矩阵。。学会这题真心涨姿势。

        解题过程是这样的。除去第一行,把第一列看成是一个列向量v(由输入的那些数组成),v=(a1,a2,a3......)。然后我们可以往右推,看看每推一列,这个向量发生了什么,容易得到第二列(a1,a1+a2,a1+a2+a3......),可以把它看成是(b1,b2,b3......),继续往后推,还是有这样的规律。我们就可以构造如下方阵。


1 0 0 0 ...

1 1 0 0 ...

1 1 1 0 ...

1 1 1 1 ...

......

只要该元素参与求和,对应的方阵上的元素就是1,否则为0。

        加上第一行以后,容易发现第一行每个元素是上一个元素乘以10再加上3,所以完整的列向量就是(a1,a2,a2,...,23,3)。完整的方阵是:

1 0 0 0 ... |10 1 

1 1 0 0 ... |10 1

1 1 1 0 ... |10 1

1 1 1 1 ... |10 1

......      ... | ...

--------------------

0 0 0 0 ... |10 1

0 0 0 0 ... |  0 1

        最后就是矩阵快速幂,求方阵的m次方,右乘上列向量,取结果的第n个数,完成。一句话总结:矩阵真是描述变换的好工具!


#include <iostream>           
#include <stdio.h>           
#include <cmath>           
#include <algorithm>           
#include <iomanip>           
#include <cstdlib>           
#include <string>           
#include <string.h>           
#include <vector>           
#include <queue>           
#include <stack>           
#include <map>         
#include <assert.h>
#include <set>         
#include <ctype.h>                
#define ll long long       
#define max3(a,b,c) max(a,max(b,c))       

using namespace std; 

const ll mod=1E7+7;

struct mat{
	ll v[16][16];
	mat(){
		memset(v,0,sizeof(v));
	}
};

mat mat_mul(mat a,mat b,int siz){
	mat re;
	for(int i=0;i<siz;i++){
		for(int j=0;j<siz;j++){
			for(int k=0;k<siz;k++){
				re.v[i][j]+=a.v[i][k]*b.v[k][j];
				re.v[i][j]%=mod;
			}
		}
	}
	return re;
}

mat mat_pow(mat m,int n,int siz){
	mat re;
	mat tmp=m;
	for(int i=0;i<siz;i++){
		re.v[i][i]=1;
	}
	while(n){
		if(n&1){
			re=mat_mul(re,tmp,siz);
		}
		tmp=mat_mul(tmp,tmp,siz);
		n>>=1;
	}
	return re;
}

int main(){
	int n,m;
	while(cin>>n>>m){
		mat vec;
		mat a;
		for(int i=0;i<n;i++){
			cin>>vec.v[i][0];
		}
		vec.v[n][0]=23;
		vec.v[n+1][0]=3;
		
		for(int i=0;i<n;i++){
			for(int j=0;j<=i;j++){
				a.v[i][j]=1;
			}
			a.v[i][n]=10;
			a.v[i][n+1]=1;
		}
		a.v[n][n]=10;
		a.v[n][n+1]=1;
		a.v[n+1][n+1]=1;
		
		mat am=mat_pow(a,m,n+2);
		mat ans;
		ans=mat_mul(am,vec,n+2);
		
		cout<<ans.v[n-1][0]<<endl;;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值