HDU5015_233 Matrix(矩阵快速幂,递推转矩阵)

题意:

给定矩阵的第一行和第一列,其余每项 a [ i ] [ j ] = a [ i − 1 ] [ j ] + a [ i ] [ j − 1 ] a[i][j] = a[i-1][j] + a[i][j-1] a[i][j]=a[i1][j]+a[i][j1],求 a n , m % 10000007 a_{n,m}\% 10000007 an,m%10000007

数据范围:

n < = 10 , m < = 1 0 9 , 0 < = a 1 , 0 , a 2 , 0 , . . . , a n , o < 2 31 n<=10,m<=10^9,0<=a_{1,0},a_{2,0},...,a_{n,o}<2^{31} n<=10,m<=1090<=a1,0,a2,0,...,an,o<231

思路:

首先第0行为0, 233, 23333...,为了使递推式 a 0 , j = 10 ∗ a 0 , j − 1 + 3 a_{0,j}=10*a_{0,j-1}+3 a0,j=10a0,j1+3成立,把第一个0变为23,即 a 0 , 0 a_{0,0} a0,0视作23。

  • 第 0 行, a 0 , j = 10 a 0 , j − 1 + 3 a_{0,j}=10a_{0,j-1}+3 a0,j=10a0,j1+3
  • 第 1 行, a 1 , j = a 1 , j − 1 + a 0 , j = a 1 , j − 1 + 10 a 0 , j − 1 + 3 a_{1,j}=a_{1,j-1}+a_{0,j}=a_{1,j-1}+10a_{0,j-1}+3 a1,j=a1,j1+a0,j=a1,j1+10a0,j1+3
  • 第 2 行, a 2 , j = a 2 , j − 1 + a 1 , j = a 2 , j − 1 + a 1 , j − 1 + 10 a 0 , j − 1 + 3 a_{2,j}=a_{2,j-1}+a_{1,j}=a_{2,j-1}+a_{1,j-1}+10a_{0,j-1}+3 a2,j=a2,j1+a1,j=a2,j1+a1,j1+10a0,j1+3
  • … …
  • 第 n 行, a n , j = ∑ i = 1 n a i , j − 1 + 10 a 0 , j − 1 + 3 a_{n,j}=\sum_{i=1}^{n}a_{i,j-1}+10a_{0,j-1}+3 an,j=i=1nai,j1+10a0,j1+3
    重点是怎么构造矩阵呢?
    线代知识,把等式左边构成一列向量,等式右边的系数就是系数矩阵(也就是所要求的构造矩阵)。当时在求大数fibonacci项时, f n = f n − 1 + f n − 2 f_n=f_n{-1}+f_{n-2} fn=fn1+fn2只需构造一个2*2矩阵即可。而这里最后存在非线性项+3,要给左边的列向量,n + 1 行增广一个常数 1,共 n + 2 行

将上面的递推写成矩阵形式
在这里插入图片描述
可以看出后一列可由前一列递推得来。要求 a n , m a_{n,m} an,m,也就是第 m 列的情况,递推得:
在这里插入图片描述
矩阵的 m 次幂可用矩阵快速幂解决。
最后 a n , m = ∑ j = 0 n + 1 a n s [ n ] [ j ] ∗ c o l [ j ] a_{n,m}=\sum_{j=0}^{n+1}ans[n][j] * col[j] an,m=j=0n+1ans[n][j]col[j]

input:
1 1
1
2 2
0 0
3 7
23 47 16
output:
234
2799
72937

#include<cstdio>
#include<iostream>
#include<cstring> 
using namespace std;
typedef long long ll;
const int maxn=12; //矩阵最多 12 阶 
const int MOD=10000007;
int col[maxn]; //矩阵第一列 
int n,m;
struct matrix{
	ll a[maxn][maxn];
	void init()
	{
		memset(a,0,sizeof a);
		for(int i = 0; i < n + 2; i++)
			a[i][i] = 1;
	} 
};
matrix mul(matrix p, matrix q)
{
	matrix ans;
	for(int i = 0; i < n + 2; i++)
	{
		for(int j = 0; j < n + 2; j++)
		{
			ans.a[i][j] = 0;
			for(int k = 0; k < n + 2; k++)
				ans.a[i][j] = (ans.a[i][j] + p.a[i][k] * q.a[k][j])%MOD;
		}
	}
	return ans;
}
matrix qpow(matrix tag, int k)  //矩阵快速幂 
{
	matrix ans;
	ans.init();
	while(k)
	{
		if(k&1)
			ans = mul(ans, tag);
		tag = mul(tag, tag);
		k>>=1;
	}
	return ans;
}
int main()
{
	while(cin>>n>>m)
	{
		col[0]=23; //输入第一列 
		for(int i = 1; i <= n; i++)
			cin>>col[i];
		col[n+1]=1;
		
		matrix ans; //开始构造矩阵 
		ans.init();
		for(int i = 0; i <= n; i++) //纸上写好,往里填就可以
		{
			ans.a[i][0]=10;
			for(int j = 1; j <= i; j++)
				ans.a[i][j] = 1;
			ans.a[i][n+1] = 3;
			ans.a[n+1][i] = 0;
		}
		ans.a[n+1][n+1] = 1;
		
		ans = qpow(ans,m); //ans的 m 次幂 
		ll res = 0;
		for(int j = 0; j < n + 2; j++)  //第 n 行累加求和 
			res = (res + ans.a[n][j] * col[j])%MOD;
		cout<<res<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值