hdu5015(2014西安网赛) 233 Matrix

        题意:一个矩阵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;
}


你可能感兴趣的:(矩阵快速幂,2014西安网赛)